package com.zyh.scs.admin.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.handler.inter.IExcelExportServer;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyh.scs.admin.api.constant.*;
import com.zyh.scs.admin.api.dto.TransactionBillDTO;
import com.zyh.scs.admin.api.dto.open.DeptSyncDTO;
import com.zyh.scs.admin.api.dto.open.UserSyncDTO;
import com.zyh.scs.admin.api.entity.*;
import com.zyh.scs.admin.api.entity.jd.JdOrderSku;
import com.zyh.scs.admin.api.utils.UserTypeToNameUtil;
import com.zyh.scs.admin.api.vo.*;
import com.zyh.scs.admin.api.vo.account.*;
import com.zyh.scs.admin.base.LaoSheFanWeiResponse;
import com.zyh.scs.admin.mapper.*;
import com.zyh.scs.admin.mapper.jd.JdOrderMapper;
import com.zyh.scs.admin.mapper.jd.JdOrderSkuMapper;
import com.zyh.scs.admin.service.SysUserService;
import com.zyh.scs.admin.service.UserDepartmentInfoService;
import com.zyh.scs.admin.service.UserPsnInfoService;
import com.zyh.scs.admin.utils.MkbReqUtil;
import com.zyh.scs.common.core.util.MinioUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author hwh
 * @ClassName: 泛微导出员工人员信息api接口实现类$
 * @Description: $
 * @Date $
 * @Version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserPsnInfoServiceImpl extends ServiceImpl<UserPsnInfoMapper, UserPsnInfo> implements UserPsnInfoService {

    private final UserPsnInfoMapper userPsnInfoMapper;

    private final MkbReqUtil mkbReqUtil;

    private final SysUserMapper sysUserMapper;

    private final UserBillMapper userBillMapper;

    private final UserStaffInfoMapper userStaffInfoMapper;

    private final UserEarlyWarnMapper userEarlyWarnMapper;

    private final UserTransactionMapper userTransactionMapper;

    private final MinioUtil minioUtil;

    private final UserDepartmentInfoMapper userDepartmentInfoMapper;

    private final UserDepartmentInfoService userDepartmentInfoService;

    private final SysPostMapper sysPostMapper;

    private final SysUserService sysUserService;

    private final UserOrderInfoMapper userOrderInfoMapper;

    private final JdOrderSkuMapper jdOrderSkuMapper;

    private final JdOrderMapper jdOrderMapper;


    private final String XLSX = ".xlsx";

    /**
     * redis客户端
     */
    private final RedissonClient redissonClient;

    private final String USER_TASK_KEY = "USER_TASK_KEY";

    /**
     * 满客宝机构信息同步接口
     */
    @Value("${mannKeBao.api.sync-add-supplierOrg}")
    public String API_SYNC_ADD_SUPPLIER_ORG;

    /**
     * 满客宝用户信息同步接口
     */
    @Value("${mannKeBao.api.sync-add-supplierUser}")
    public String API_SYNC_ADD_SUPPLIER_USER;


    @Override
    public void warmUser() {
        //同步用户发送预警
        log.info("同步用户发送预警 <<<<< 开始时间: {}", LocalDateTime.now());
        synchronous();
        log.info("同步用户发送预警 <<<<< 结束时间: {}", LocalDateTime.now());
        //冻结泛微缺少用户
        log.info("冻结泛微缺少用户 <<<<< 开始时间: {}", LocalDateTime.now());
        lock();
        log.info("冻结泛微缺少用户 <<<<< 结束时间: {}", LocalDateTime.now());
    }


    @Override
    public LaoSheFanWeiResponse pullManKeBaoUserInfo(List<SysUser> sysUserList) {

        List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoService.list();
        List<SysUser> userInfoUpdateList = new ArrayList<>(sysUserList.size());
        // 调用满客宝
        for (SysUser sysUser : sysUserList) {

            if (null == sysUser) {
                continue;
            }

            if (sysUser.getPullStatus() == 1) {

                UserSyncDTO dto = new UserSyncDTO();

                dto.setGuid(sysUser.getGuid());
                dto.setUpdateType(MKBApiOrgUpdateType.INSERT.getCode());
                dto.setMobile(sysUser.getPhone());
                dto.setName(sysUser.getUsername());

                dto.setCardId(sysUser.getUserMealsNumber());
                dto.setStatus(sysUser.getLockFlag().equals(UserStateEnum.NORMAL.getCode()) ? "1" : "2");
                dto.setUserJobNum(sysUser.getUserJobNumber());
                if (StrUtil.isNotBlank(sysUser.getThirdDeptId())) {
                    dto.setDeptId(sysUser.getThirdDeptId());
                    List<UserDepartmentInfo> infoList = userDepartmentInfoList.stream().filter(Objects::nonNull)
                            .filter(bb -> StrUtil.isNotBlank(bb.getDeptId()))
                            .filter(cc -> cc.getDeptId().equals(sysUser.getThirdDeptId())).toList();

                    if (!infoList.isEmpty()) {
                        UserDepartmentInfo userDepartmentInfo = infoList.stream().findFirst().get();
                        dto.setDeptName(StrUtil.isNotBlank(userDepartmentInfo.getOrgShortName()) ? userDepartmentInfo.getOrgShortName() : "");
                    }

                }

                LaoSheFanWeiResponse rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_USER, JSON.toJSONString(dto));

                // 推送状态更新为已同步
                SysUser userInfoUpdate = new SysUser();
                userInfoUpdate.setUserId(sysUser.getUserId());
                userInfoUpdate.setUpdateTime(LocalDateTime.now());
                userInfoUpdate.setUpdateBy("pullManKeBaoUserInfo");
                // 调用成功
                if (null != rs) {

                    if (Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {
                        userInfoUpdate.setPullStatus(2);
                        // 卡号已存在--更新操作
                    } else if (100009 == rs.getRetCode()) {
                        if (rs.getRetMsg().contains("用户编号") && rs.getRetMsg().contains("已被占用")) {
                            userInfoUpdate.setPullStatus(5);
                        } else if (rs.getRetMsg().contains("手机号") && rs.getRetMsg().contains("已被占用")) {
                            userInfoUpdate.setPullStatus(4);
                        } else if (rs.getRetMsg().contains("卡号已存在")) {
                            userInfoUpdate.setPullStatus(6);
                        } else {
                            dto.setUpdateType(MKBApiOrgUpdateType.UPDATE.getCode());
                            rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_USER, JSON.toJSONString(dto));

                            if (null != rs && Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {
                                userInfoUpdate.setPullStatus(2);
                            }
                        }
                    }
                }
                userInfoUpdateList.add(userInfoUpdate);
            }
        }

        sysUserService.updateBatchById(userInfoUpdateList);
        return LaoSheFanWeiResponse.success("同步满客宝员工成功");
    }

    public LaoSheFanWeiResponse pushAddUser() {
        List<SysUser> userInfoList = sysUserMapper.selectList(new QueryWrapper<SysUser>()
                .lambda()
                // 员工类型 1-内部员工 2-委外员工 3-见习员工
                .in(SysUser::getUserType, 1, 2, 3)
                // 2未同步
                .eq(SysUser::getPullStatus, 3));
        log.info("add >>>  data: {}", JSON.toJSONString(userInfoList));
        pullManKeBaoUserInfo(userInfoList);

        return LaoSheFanWeiResponse.success("同步完成");
    }


    @Override
    public LaoSheFanWeiResponse pushUser() {
        List<SysUser> userInfoList = sysUserMapper.selectList(new QueryWrapper<SysUser>()
                .lambda()
                // 员工类型 1-内部员工 2-委外员工 3-见习员工
                .in(SysUser::getUserType, 1, 2, 3)
                // 2未同步
                .in(SysUser::getPullStatus, QWPullStatus.UNSYNC.getCode(), 3));
        log.info("syncUser >>>  data: {}", JSON.toJSONString(userInfoList));
        pullManKeBaoUserInfo(userInfoList);

        return LaoSheFanWeiResponse.success("同步完成");
    }

    @Override
    public LaoSheFanWeiResponse pushDepartment() {
        // 获取未同步部门列表数据
        List<UserDepartmentInfo> departmentList = userDepartmentInfoMapper.selectList(new QueryWrapper<UserDepartmentInfo>().lambda()
                // 2未同步
                .eq(UserDepartmentInfo::getPullStatus, QWPullStatus.UNSYNC.getCode()));

        List<UserDepartmentInfo> updateDepartmentList = new ArrayList<>();
        // 调用满客宝
        for (UserDepartmentInfo department : departmentList) {

            UserDepartmentInfo currentDepartment = userDepartmentInfoMapper
                    .selectOne(new QueryWrapper<UserDepartmentInfo>()
                            .lambda().eq(UserDepartmentInfo::getDeptId, department.getDeptId())
                            .last(" limit 0,1"));

            if (Objects.equals(QWPullStatus.SYNCED.getCode(), currentDepartment.getPullStatus())) {
                log.error("推送部门 >>> 该部门已同步，department: {}", JSON.toJSONString(department));
                continue;
            }

            // 递归检查父级是否已同步，否-同步
            String parentId = department.getParentId();

            if (StrUtil.isEmpty(parentId)) {
                log.error("推送部门 >>> 异常部门，该部门未关联父级ID，department: {}", JSON.toJSONString(department));
                continue;
            }

            // 递归同步未同步的父级部门 (商户同步的部门)
            asyncMchParentDepartment(parentId);

            DeptSyncDTO dto = new DeptSyncDTO();

            dto.setDeptId(department.getDeptId());
            dto.setDeptName(department.getOrgShortName());
            dto.setParentId(department.getParentId());
            dto.setUpdateType(MKBApiOrgUpdateType.INSERT.getCode());

            LaoSheFanWeiResponse rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_ORG, JSON.toJSONString(dto));

            // 调用成功
            if (null != rs && Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {

                // 推送状态更新为已同步
                UserDepartmentInfo departmentUpdate = new UserDepartmentInfo();

                departmentUpdate.setId(department.getId());
                departmentUpdate.setPullStatus(QWPullStatus.SYNCED.getCode());
                updateDepartmentList.add(departmentUpdate);
            }

        }
        userDepartmentInfoService.updateBatchById(updateDepartmentList);

        return LaoSheFanWeiResponse.success("更新商户同步的部门成功");
    }

    public boolean pull() {
        List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoService.list(Wrappers.<UserDepartmentInfo>lambdaQuery()
                .eq(UserDepartmentInfo::getPullStatus, 1));

        userDepartmentInfoList.stream().filter(Objects::nonNull).filter(a -> StrUtil.isNotBlank(a.getDeptId())).forEach(department -> {
            department.setPullStatus(2);
            this.pushDeptId(department.getDeptId());
        });

        List<SysUser> sysUserList = sysUserService.list(Wrappers.<SysUser>lambdaQuery()
                .in(SysUser::getPullStatus, 1, 3));

        sysUserList.stream().filter(Objects::nonNull).filter(a -> StrUtil.isNotBlank(a.getGuid())).forEach(sysUser -> {
            sysUser.setPullStatus(2);
            this.pushUser(sysUser.getGuid());
        });

        return Boolean.TRUE;
    }

    @Override
    public LaoSheFanWeiResponse pushDeptId(String deptId) {

        log.info("部门id :{}", deptId);
        UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                .eq(UserDepartmentInfo::getDeptId, deptId)
                .last(" limit 1"));

        DeptSyncDTO dto = new DeptSyncDTO();

        dto.setDeptId(userDepartmentInfo.getDeptId());
        dto.setDeptName(userDepartmentInfo.getOrgShortName());
        dto.setParentId(userDepartmentInfo.getParentId());
        dto.setUpdateType(MKBApiOrgUpdateType.INSERT.getCode());

        LaoSheFanWeiResponse rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_ORG, JSON.toJSONString(dto));

        if (rs != null) {
            if (Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {
                // 推送状态更新为已同步
                UserDepartmentInfo departmentUpdate = new UserDepartmentInfo();

                departmentUpdate.setId(userDepartmentInfo.getId());
                departmentUpdate.setPullStatus(QWPullStatus.SYNCED.getCode());

                userDepartmentInfoMapper.updateById(departmentUpdate);
            }
        }
        return LaoSheFanWeiResponse.success("该部门id:" + deptId + "同步的部门成功");
    }

    @Override
    public LaoSheFanWeiResponse pushUser(String guid) {
        SysUser sysUser = sysUserMapper.selectByGuid(guid);

        UserSyncDTO dto = new UserSyncDTO();

        dto.setGuid(guid);
        dto.setUpdateType(MKBApiOrgUpdateType.INSERT.getCode());
        dto.setMobile(sysUser.getPhone());
        dto.setName(sysUser.getUsername());
        dto.setCardId(sysUser.getUserMealsNumber());
        dto.setStatus(sysUser.getLockFlag().equals(UserStateEnum.NORMAL.getCode()) ? "1" : "2");
        dto.setUserJobNum(sysUser.getUserJobNumber());
        if (StrUtil.isNotBlank(sysUser.getThirdDeptId())) {
            dto.setDeptId(sysUser.getThirdDeptId());
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery().eq(UserDepartmentInfo::getDeptId, sysUser.getThirdDeptId()).last(" limit 1"));
            dto.setDeptName(userDepartmentInfo != null && StrUtil.isNotBlank(userDepartmentInfo.getOrgShortName()) ? userDepartmentInfo.getOrgShortName() : null);
        }

        LaoSheFanWeiResponse rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_USER, JSON.toJSONString(dto));

        // 调用成功
        if (null != rs) {

            if (Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {

                // 推送状态更新为已同步
                SysUser userInfoUpdate = new SysUser();

                userInfoUpdate.setPullStatus(2);
                userInfoUpdate.setUserId(sysUser.getUserId());

                sysUserMapper.updateById(userInfoUpdate);
                // 卡号已存在--更新操作
            } else if (100009 == rs.getRetCode()) {
                SysUser updateUser = new SysUser();
                updateUser.setUserId(sysUser.getUserId());
                if (rs.getRetMsg().contains("用户编号") && rs.getRetMsg().contains("已被占用")) {
                    updateUser.setPullStatus(5);
                    sysUserMapper.updateById(updateUser);
                } else if (rs.getRetMsg().contains("手机号") && rs.getRetMsg().contains("已被占用")) {
                    updateUser.setPullStatus(4);
                    sysUserMapper.updateById(updateUser);
                } else if (rs.getRetMsg().contains("卡号已存在")) {
                    updateUser.setPullStatus(6);
                    sysUserMapper.updateById(updateUser);
                } else if (rs.getRetMsg().contains("工号手机号不能同时为空")) {
                    updateUser.setPullStatus(7);
                    sysUserMapper.updateById(updateUser);
                } else {
                    dto.setUpdateType(MKBApiOrgUpdateType.UPDATE.getCode());
                    rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_USER, JSON.toJSONString(dto));

                    if (null != rs && Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) {

                        // 推送状态更新为已同步
                        SysUser userInfoUpdate = new SysUser();

                        userInfoUpdate.setPullStatus(2);
                        userInfoUpdate.setUserId(sysUser.getUserId());

                        sysUserMapper.updateById(userInfoUpdate);
                    }
                }

            }
        }

        return LaoSheFanWeiResponse.success("同步完成");
    }

    /**
     * 递归同步未同步的父级部门 (商户同步的部门)
     *
     * @param parentId
     */
    private void asyncMchParentDepartment(String parentId) {

        UserDepartmentInfo department = userDepartmentInfoMapper.selectOne(new QueryWrapper<UserDepartmentInfo>().lambda().eq(UserDepartmentInfo::getDeptId, parentId).last(" limit 0,1"));

        if (null == department) {
            log.error("推送部门 >>> 该父部门不存在，parentId: {}, department: {}", parentId, JSON.toJSONString(department));
            return;
        }

        // 递归检查父级是否已同步，否-同步
        String currentParentId = department.getParentId();

        if (StrUtil.isEmpty(currentParentId)) {
            log.error("推送部门 >>> 异常部门，该父部门未关联父级ID，parentId: {}, department: {}", parentId, JSON.toJSONString(department));
            return;
        }

        // 递归同步未同步的父级部门
        asyncMchParentDepartment(currentParentId);

        if (Objects.equals(QWPullStatus.SYNCED.getCode().toString(), department.getPullStatus())) {
            log.error("推送部门 >>> 该父部门已同步，parentId: {}, department: {}", parentId, JSON.toJSONString(department));
            return;
        }

        DeptSyncDTO dto = new DeptSyncDTO();

        dto.setDeptId(department.getDeptId());
        dto.setDeptName(department.getOrgShortName());
        dto.setParentId(department.getParentId());
        dto.setUpdateType(MKBApiOrgUpdateType.INSERT.getCode());

        LaoSheFanWeiResponse rs = mkbReqUtil.post(API_SYNC_ADD_SUPPLIER_ORG, JSON.toJSONString(dto));

        if (null != rs && Objects.equals(CodeSet.SUCCESS_CODE.getCode(), rs.getRetCode())) { // 调用成功

            // 推送状态更新为已同步
            UserDepartmentInfo departmentUpdate = new UserDepartmentInfo();

            departmentUpdate.setId(department.getId());
            departmentUpdate.setPullStatus(QWPullStatus.SYNCED.getCode());

            userDepartmentInfoMapper.updateById(departmentUpdate);
        }
    }


    @Override
    public LaoSheFanWeiResponse pushMkbDepAndUser() {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "pushMkbDepAndUser");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            log.info("3.1 定时推送部门到满客宝 <<<<< 开始时间: {}", LocalDateTime.now());
            pushDepartment();
            log.info("3.2 定时推送部门到满客宝 <<<<< 开始时间: {}", LocalDateTime.now());
//        log.info("3.3 定时推送新增到满客宝 <<<<< 开始时间: {}", LocalDateTime.now());
//        pushAddUser();
//        log.info("3.4 定时推送新增到满客宝 <<<<< 结束时间: {}", LocalDateTime.now());
            log.info("3.5 定时推送人员到满客宝 <<<<< 开始时间: {}", LocalDateTime.now());
            pushUser();
            log.info("3.6 定时推送人员到满客宝 <<<<< 结束时间: {}", LocalDateTime.now());
            return LaoSheFanWeiResponse.success("同步完成");
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean synchronous() {
        //拿出新增的数据对比
        log.info("同步用户并发送预警 <<<<< 开始时间: {}", LocalDateTime.now());
        List<UserPsnInfo> userPsnInfoList = userPsnInfoMapper
                .selectList(Wrappers.<UserPsnInfo>lambdaQuery()
                        .eq(UserPsnInfo::getIsInsert, 2)
                        .eq(UserPsnInfo::getApplyEvent, "2"));
        log.info("同步用户并发送预警 <<<<< psn个数: {}", userPsnInfoList.size());
        //获取泛微同步的数据 userList
        List<SysUser> sysUserList = sysUserMapper
                .selectList(Wrappers.<SysUser>lambdaQuery()
                        .eq(SysUser::getIsAdmin, 1)
                        .eq(SysUser::getDelFlag, 0));

        //岗位
        List<SysPost> sysPostAllList = sysPostMapper.selectList(null);

        //循环对比
        userPsnInfoList.forEach(a -> {
            log.info("同步用户并发送预警 <<<<< psn: {}", a.getPsnId());
            UserStaffInfo userStaffInfo = userStaffInfoMapper.selectOne(Wrappers.<UserStaffInfo>lambdaQuery()
                    .eq(StrUtil.isNotBlank(a.getPsnId()), UserStaffInfo::getPsnId, a.getPsnId())
                    //筛选出 1和2的  3为物理删除
                    .in(UserStaffInfo::getApplyEvent, "1", "2")
                    .last(" limit 1"));
            if (sysUserList.stream().map(SysUser::getPsnId)
                    .filter(Objects::nonNull).toList().contains(a.getPsnId())) {
                //此时存在相同psnId的值 覆盖
                SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                        .eq(StrUtil.isNotBlank(a.getPsnId()), SysUser::getPsnId, a.getPsnId())
                        .last(" limit 1"));
                //工号
                sysUser.setUserJobNumber(a.getPsnCode());
                sysUser.setUsername(a.getPsnName());
                if (StrUtil.isNotBlank(a.getMobile())) {
                    sysUser.setPhone(a.getMobile());
                }
                //通过PsnId去拿到部门 公司
                if (userStaffInfo != null) {
                    sysUser.setThirdDeptId(userStaffInfo.getDeptId());
                    UserDepartmentInfo companyDepart = userDepartmentInfoMapper
                            .selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                                    .eq(StrUtil.isNotBlank(userStaffInfo.getCorpId()),
                                            UserDepartmentInfo::getDeptId, userStaffInfo.getCorpId())
                                    .last(" limit 1"));
                    if (companyDepart != null) {
                        sysUser.setCompanyId(companyDepart.getId());
                    }

                    List<SysPost> sysPostList = sysPostAllList.stream()
                            .filter(Objects::nonNull).filter(p -> p.getPostCode()
                                    .equals(userStaffInfo.getCorpId())).toList();
                    if (!sysPostList.isEmpty()) {
                        sysUser.setPostId(sysPostList.get(0).getPostId());
                    }
                }
                //用户状态开启
                sysUser.setLockFlag("0");
                sysUser.setCardState("1");
                sysUser.setCashState("1");
                sysUser.setPullStatus(1);
                sysUser.setUpdateTime(LocalDateTime.now());
                sysUser.setCardAccount(null);//不修改此字段
                sysUser.setCashAccount(null);//不修改此字段
                sysUserMapper.updateById(sysUser);
                //预警效验
                validWarn(a, sysUser);
                a.setIsInsert(1);
                userPsnInfoMapper.updateById(a);
            } else if (sysUserList.stream().map(SysUser::getUserJobNumber)
                    .filter(Objects::nonNull).toList().contains(a.getPsnCode())) {
                //一致的话传入预警提示中和user表中
                SysUser sysUser = new SysUser();
                if (sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                        .eq(SysUser::getPsnId, a.getPsnId())).isEmpty()) {
                    insertUser(a, sysUser, userStaffInfo);
                }
                //新用户新增
                if (StrUtil.isNotBlank(sysUser.getUsername())) {
                    if (sysUser.getDataSources().equals("1")) {
                        sysUser.setUpdateTime(LocalDateTime.now());
                        sysUserMapper.insert(sysUser);
                    }
                }
                //预警效验
                validWarn(a, sysUser);
                a.setIsInsert(1);
                userPsnInfoMapper.updateById(a);
            } else {
                SysUser sysUser = new SysUser();
                if (sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPsnId, a.getPsnId())).isEmpty()) {
                    insertUser(a, sysUser, userStaffInfo);
                }
                //新用户新增
                if (StrUtil.isNotBlank(sysUser.getUsername())) {
                    if (sysUser.getDataSources().equals("1")) {
                        sysUser.setUpdateTime(LocalDateTime.now());
                        sysUserMapper.insert(sysUser);
                    }
                }
                a.setIsInsert(1);
                userPsnInfoMapper.updateById(a);
            }
        });
        log.info("同步用户并发送预警 <<<<< 结束时间: {}", LocalDateTime.now());
        return Boolean.TRUE;
    }

    @Override
    public boolean lock() {
        //获取到昨天的日期
        List<SysUser> sysUserList = sysUserMapper
                .selectList(Wrappers.<SysUser>lambdaQuery()
                        .eq(SysUser::getDataSources, 1)
                        .le(SysUser::getUpdateTime, LocalDateTime.now().minusDays(1)));
        //全部禁用
        sysUserList.forEach(a -> {
            a.setLockFlag("9");
            a.setCardState("2");
            a.setCashState("2");
            a.setPullStatus(1);
            a.setUpdateTime(LocalDateTime.now());
            a.setCardAccount(null);//不修改此字段
            a.setCashAccount(null);//不修改此字段
            sysUserMapper.updateById(a);
        });
        return Boolean.TRUE;
    }

    private void validWarn(UserPsnInfo a, SysUser sysUser) {
        List<UserEarlyWarn> userRepeatWarnList = userEarlyWarnMapper
                .selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                        .eq(StrUtil.isNotBlank(a.getPsnCode()), UserEarlyWarn::getUserJobNumber, a.getPsnCode())
                        .eq(UserEarlyWarn::getResult, 1)
                        .ge(UserEarlyWarn::getCreateTime, UserTypeToNameUtil.stringToLocalBeginTime(LocalDate.now().toString()))
                        .le(UserEarlyWarn::getCreateTime, UserTypeToNameUtil.stringToLocalEndTime(LocalDate.now().toString()))
                        .orderByDesc(UserEarlyWarn::getCreateTime));
        //当天存在的所有预警信息  分组
        List<List<UserEarlyWarn>> warnListsSet = new ArrayList<>();
        if (!userRepeatWarnList.isEmpty()) {
            //查询是否存在重复预警
            userRepeatWarnList.forEach(id -> {
                List<UserEarlyWarn> userList = new ArrayList<>();
                if (id.getNewId() != null) {
                    //该预警为新账号
                    List<UserEarlyWarn> userWarnListNew = userEarlyWarnMapper
                            .selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                                    .eq(UserEarlyWarn::getResult, 1)
                                    .eq(UserEarlyWarn::getNewId, id.getNewId())
                                    .orderByDesc(UserEarlyWarn::getCreateTime));
                    userList.addAll(userWarnListNew);
                    //找到新id
                    userList.add(userEarlyWarnMapper.selectById(id.getNewId()));
                    warnListsSet.add(userList);
                } else {
                    //为旧账号
                    List<UserEarlyWarn> userWarnListOld = userEarlyWarnMapper.selectList(Wrappers.<UserEarlyWarn>lambdaQuery()
                            .eq(UserEarlyWarn::getResult, 1)
                            .eq(UserEarlyWarn::getNewId, id.getWarnId())
                            .orderByDesc(UserEarlyWarn::getCreateTime));
                    userList.addAll(userWarnListOld);
                    userList.add(id);
                    warnListsSet.add(userList);
                }
            });
        }
        //warnList去重
        Set<List<UserEarlyWarn>> uniqueSet = new HashSet<>(warnListsSet);
        //去重后的warnList
        List<List<UserEarlyWarn>> warnList = new ArrayList<>(uniqueSet);
        //查询出有没有工号一样,psnId一样的
        List<SysUser> userPsnNumberList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserJobNumber, a.getPsnCode()).eq(SysUser::getDataSources, "1")
                .eq(SysUser::getIsAdmin, 1));
        if (!userPsnNumberList.isEmpty()) {
            //此时存在 判断条数  此时多一条当前创建的
            if (userPsnNumberList.size() > 2) {
                //筛选出正常的
                userPsnNumberList = userPsnNumberList.stream()
                        .filter(flag -> Objects.equals(flag.getLockFlag(), UserStateEnum.NORMAL.getCode())).toList();
            }
        }
        //如果userPsnList 不为空时且大于1时发预警
        if (!userPsnNumberList.isEmpty() && userPsnNumberList.size() > 1) {
            //此时需要发预警 判断预警信息是否重复
            List<Long> userIdList = userPsnNumberList.stream().map(SysUser::getUserId).toList();
            //通过userId对比
            //TODO 今天生成的预警信息 分组
            boolean flag = true;
            if (!warnList.isEmpty()) {
                //筛选
                for (List<UserEarlyWarn> userEarlyWarnList : warnList) {
                    //TODO 今天生成的预警信息 userIdList集合
                    List<Long> screenList = userEarlyWarnList.stream().map(UserEarlyWarn::getUserId).toList();
                    //TODO 当天新增覆盖  减少新增
                    if (new HashSet<>(userIdList).containsAll(screenList)) {
                        //包含覆盖  将原预警删除  新增预警
                        userEarlyWarnMapper.deleteBatchIds(userEarlyWarnList.stream()
                                .map(UserEarlyWarn::getWarnId).toList());
                        break;
                    } else if (new HashSet<>(screenList).containsAll(userIdList)) {
                        //此时不新增  预警包含
                        flag = false;
                        break;
                    }
                }
            }
            // 预警信息为空  新增预警
            if (flag) {
                insertWarn(a, sysUser, userPsnNumberList);
            }
        }
    }

    private void insertWarn(UserPsnInfo a, SysUser sysUser, List<SysUser> userPsnNumberList) {
        //生成预警信息
        UserEarlyWarn userEarlyWarnNew = getUserEarlyWarn(a, sysUser);
        userEarlyWarnNew.setEarlyType("1");
        userEarlyWarnNew.setUserId(sysUser.getUserId());
        if (StrUtil.isNotBlank(a.getMobile())) {
            userEarlyWarnNew.setPhone(sysUser.getPhone());
        }
        userEarlyWarnMapper.insert(userEarlyWarnNew);
        List<SysUser> list = userPsnNumberList.stream().filter(f -> !f.getPsnId().equals(a.getPsnId())).toList();
        list.forEach(job -> {
            //生成预警旧预警
            UserEarlyWarn userEarlyWarnOld = getUserEarlyWarn(a, job);
            userEarlyWarnOld.setCardAccount(job.getCardAccount());
            userEarlyWarnOld.setCashAccount(job.getCashAccount());
            userEarlyWarnOld.setNewUserId(sysUser.getUserId());
            userEarlyWarnOld.setUsername(job.getUsername());
            userEarlyWarnOld.setNewId(userEarlyWarnNew.getWarnId());
            userEarlyWarnOld.setPhone(job.getPhone());
            userEarlyWarnOld.setEarlyType("2");
            userEarlyWarnMapper.insert(userEarlyWarnOld);
        });
    }


    private void insertUser(UserPsnInfo a, SysUser sysUser, UserStaffInfo userStaffInfo) {
        //新的账号生成
        sysUser.setUsername(a.getPsnName());
        sysUser.setUserJobNumber(a.getPsnCode());
        sysUser.setDelFlag("0");
        sysUser.setCardState("1");
        sysUser.setCashState("1");
        sysUser.setCashAccount(BigDecimal.ZERO);
        sysUser.setCardAccount(BigDecimal.ZERO);
        sysUser.setCreateTime(LocalDateTime.now());
        sysUser.setLockFlag(UserStateEnum.NORMAL.getCode());
        sysUser.setUserType(1);
        sysUser.setPsnId(a.getPsnId());
        if (StrUtil.isNotBlank(a.getMobile())) {
            sysUser.setPhone(a.getMobile());
        }
        sysUser.setDataSources("1");
        if (StrUtil.isNotBlank(a.getMobile())) {
            sysUser.setPhone(a.getMobile());
        }
        if (userStaffInfo != null) {
            sysUser.setThirdDeptId(userStaffInfo.getDeptId());
            sysUser.setPostId(Long.valueOf(userStaffInfo.getJobCode()));
            UserDepartmentInfo companyDepart = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery().eq(StrUtil.isNotBlank(userStaffInfo.getCorpId()), UserDepartmentInfo::getDeptId, userStaffInfo.getCorpId()).last(" limit 1"));
            if (companyDepart != null) {
                sysUser.setCompanyId(companyDepart.getId());
            }
        }
        sysUser.setPullStatus(1);
        sysUser.setTenantId(1L);
        sysUser.setUserAccount(UserTypeToNameUtil.setRechargeStream());
    }

    private static @NotNull UserEarlyWarn getUserEarlyWarn(UserPsnInfo userPsnInfo, SysUser sysUser) {
        UserEarlyWarn userEarlyWarn = new UserEarlyWarn();
        userEarlyWarn.setUserId(sysUser.getUserId());
        userEarlyWarn.setUsername(userPsnInfo.getPsnName());
        userEarlyWarn.setUserJobNumber(userPsnInfo.getPsnCode());
        userEarlyWarn.setCreateBy(userPsnInfo.getPsnName());
        userEarlyWarn.setDelFlag("0");
        userEarlyWarn.setResult("1");
        userEarlyWarn.setEarlyType("2");
        userEarlyWarn.setRepeatField("userJobNumber");
        return userEarlyWarn;
    }

    @Override
    public UserBill insertBill(Integer billType, LocalDateTime now) {
        log.info("账单生成开始时间 >>>> time:{}", LocalDateTime.now());
        UserBill userBill = new UserBill();
        //获取上个月第一天
        LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);

        // 获取上个月的年份和月份
        int year = firstDayOfLastMonth.getYear();
        int month = firstDayOfLastMonth.getMonthValue();
        userBill.setBillTime(year + "-" + month);
        log.info("账单生成时间 >>>> time:{}", year + "-" + month);
        userBill.setBillType(billType);
        log.info("账单生成类型 >>>> 类型:{}", billType);
        if (billType == 5) {
            userBill.setBillName(getFileName(100, now));
        } else {
            userBill.setBillName(getFileName(billType, now));
        }
        userBill.setCreateTime(LocalDateTime.now());
        //删除
        userBillMapper.deleteBill(year + "-" + month, billType);
        userBillMapper.insert(userBill);
        log.info("账单生成结束时间 >>>> time:{}", LocalDateTime.now());
        return userBill;
    }

    private String getExcel(Integer type, List<BillExcelVO> billExcelVOList, String fileName, String titName, String sheetName, List<BillTotalExcelVO> billTotalExcelVOList, LocalDateTime now) {
        //生成excel文档
        String bucketName = minioUtil.getBucketName();
        Workbook workbook = null;
        if (type == 1) {
            ExportParams exportParam2 = new ExportParams(now.getMonthValue() + "月交易流水账单金额合计", now.getMonthValue() + "月交易流水账单合计金额", ExcelType.HSSF);
            Map<String, Object> params2Map = new HashMap<>();
            params2Map.put("title", exportParam2);
            params2Map.put("entity", BillTotalExcelVO.class);
            params2Map.put("data", billTotalExcelVOList);
            // 将2个sheet封装
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            sheetsList.add(params2Map);
            workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
            log.info("交易流水报表workbook生成type=1 >>>> workbook:{}", workbook);
        } else {
            workbook = ExcelExportUtil.exportExcel(new ExportParams(titName, sheetName), BillExcelVO.class, billExcelVOList);
            log.info("交易流水报表workbook生成 >>>> workbook:{}", workbook);
        }
        return minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", fileName + XLSX, false);
    }

    private String getTransactionExcel(List<BillExcelVO> billExcelVOList, String fileName, String titName, String sheetName, List<BillTotalExcelVO> billTotalExcelVOList, LocalDateTime now, Workbook workbook) {
        //生成excel文档
        String bucketName = minioUtil.getBucketName();
        ExportParams exportParam1 = new ExportParams(titName, sheetName, ExcelType.HSSF);

        Map<String, Object> params1Map = new HashMap<>();
        params1Map.put("title", exportParam1);
        params1Map.put("entity", BillExcelVO.class);
        params1Map.put("data", billExcelVOList);
        ExportParams exportParam2 = new ExportParams(now.getMonthValue() + "月交易流水账单金额合计", now.getMonthValue() + "月交易流水账单合计金额", ExcelType.HSSF);
        Map<String, Object> params2Map = new HashMap<>();
        params2Map.put("title", exportParam2);
        params2Map.put("entity", BillTotalExcelVO.class);
        params2Map.put("data", billTotalExcelVOList);
        // 将2个sheet封装
        List<Map<String, Object>> sheetsList = new ArrayList<>();
        sheetsList.add(params1Map);
        sheetsList.add(params2Map);
        workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
        return minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", fileName + XLSX, false);
    }

    private String getCardAllExcel(List<UserGeneralVO> userGeneralVOList, LocalDateTime now) {
        //生成excel文档
        String fileName = now.getYear() + "年" + now.getMonthValue() + "月末餐卡总账余额表";
        String bucketName = minioUtil.getBucketName();
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(now.getYear() + "年" + now.getMonthValue() + "月末餐卡总账余额表", now.getYear() + "年" + now.getMonthValue() + "月末餐卡总账余额表"), UserGeneralVO.class, userGeneralVOList);
        return minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", fileName + XLSX, false);
    }

    private static @NotNull List<BillExcelVO> getBillExcelVOList(List<UserTransaction> userTransactionList, AtomicInteger index) {
        log.info("交易流水报表生成getBillExcelVOList生成 >>>> getBillExcelVOList:{}", index);
        List<BillExcelVO> billExcelVOList = new ArrayList<>();
        userTransactionList.forEach(a -> {
            BillExcelVO billExcelVO = new BillExcelVO();
            BeanUtil.copyProperties(a, billExcelVO);
            if (a.getTransactionType() != null) {
                billExcelVO.setTransactionType(UserTypeToNameUtil.getTransactionType(a.getTransactionType()));
            }
            if ("1".equals(a.getAccountType())) {
                billExcelVO.setRechargeTypeName(RechargeTypeEnum.MEAL_ACCOUNT.getDesc());
            } else {
                billExcelVO.setRechargeTypeName(RechargeTypeEnum.CASH_ACCOUNT.getDesc());
            }
            billExcelVO.setIndex(index.getAndIncrement());
            billExcelVOList.add(billExcelVO);
        });
        log.info("交易流水报表生成billExcelVOList生成 >>>> billExcelVOList:{}", billExcelVOList);
        return billExcelVOList;
    }

    private Map<String, LocalDateTime> getBillTimeMap(LocalDateTime now) {
        LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);
        LocalDateTime localDateBegin = firstDayOfLastMonth.withHour(0).withMinute(0).withSecond(0).withNano(0);
        //获取这个月第一天
        LocalDateTime localDateEnd = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        return Map.of("begin", localDateBegin, "end", localDateEnd);
    }

    @Override
    public boolean insertTransaction(LocalDateTime now) {
        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertTransaction");

        try {
            lock.lock(10, TimeUnit.SECONDS);

            Map<String, LocalDateTime> billTimeMap = getBillTimeMap(now);
            LocalDateTime localDateBegin = billTimeMap.get("begin");
            LocalDateTime localDateEnd = billTimeMap.get("end");
            TransactionBillDTO transactionBillDTO = new TransactionBillDTO();
            transactionBillDTO.setBeginTime(localDateBegin);
            transactionBillDTO.setEndTime(localDateEnd);
            int totalPage = userTransactionMapper.getTransactionBillCount(localDateBegin, localDateEnd);
            ExportParams exportParams = new ExportParams();
            exportParams.setTitle("交易流水账单");
            Workbook workbookOne = null;
            workbookOne = ExcelExportUtil.exportBigExcel(exportParams, BillExcelVO.class, new IExcelExportServer() {
                /**
                 * obj 就是下面的totalPage，限制条件
                 * page 是页数，他是在分页进行文件转换，page每次+1
                 */
                @Override
                public List<Object> selectListForExcelExport(Object obj, int page) {

                    IPage<BillExcelVO> billExcelListPage = userTransactionMapper.getTransactionBill(new Page<>(page, 100), transactionBillDTO);
                    if (billExcelListPage == null) {
                        return null;
                    }
                    log.info("交易流水报表billExcelList生成 >>>> billExcelList:{}", billExcelListPage);
                    return Arrays.asList(billExcelListPage.getRecords().toArray());
                }
            }, totalPage);
            //大数据导出地址
            String bigPath = minioUtil.uploadFile(minioUtil.getBucketName(), UserTypeToNameUtil.getExcelInputSteam(workbookOne), "scs/download", getFileName(1, now) + XLSX, false);
            log.info("交易流水报表bigPath生成 >>>> bigPath:{}", bigPath);
            UserBill userBill = insertBill(1, now);
            //获取excel oss地址
            String path = getExcel(1, null, getFileName(1, now), getTitName(1, now), getFileName(1, now), getListTotal(now), now.withDayOfMonth(1).minusMonths(1));
            userBill.setFilePath(bigPath);
            log.info("交易流水报表生成excel地址 >>>> path:{}", bigPath);
            userBillMapper.updateById(userBill);
            return Boolean.TRUE;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public boolean insertDeduction(LocalDateTime now) {

        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertDeduction");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            //退款
            LambdaQueryWrapper<UserTransaction> queryWrapper = getUserTransactionLambdaQueryWrapper(4, now);
            List<UserTransaction> userTransactionList = userTransactionMapper.selectList(queryWrapper);
            //生成交易流水账单
            AtomicInteger index = new AtomicInteger(1);
            List<BillExcelVO> billExcelList = getBillExcelVOList(userTransactionList, index);
            UserBill userBill = insertBill(4, now);
            //获取excel oss地址
            String path = getExcel(2, billExcelList, getFileName(4, now), getTitName(4, now), getFileName(4, now), null, now.withDayOfMonth(1).minusMonths(1));
            userBill.setFilePath(path);
            userBillMapper.updateById(userBill);
            return Boolean.TRUE;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertCard(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertCard");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            //餐卡
            LambdaQueryWrapper<UserTransaction> queryWrapper = getUserTransactionLambdaQueryWrapper(2, now);
            List<UserTransaction> userTransactionList = userTransactionMapper.selectList(queryWrapper);
            //生成交易流水账单
            AtomicInteger index = new AtomicInteger(1);
            List<BillExcelVO> billExcelList = getBillExcelVOList(userTransactionList, index);
            UserBill userBill = insertBill(2, now);
            //获取excel oss地址
            String path = getExcel(2, billExcelList, getFileName(2, now), getTitName(2, now), getFileName(2, now), null, now.withDayOfMonth(1).minusMonths(1));
            userBill.setFilePath(path);
            userBillMapper.updateById(userBill);
            return Boolean.TRUE;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertCash(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertCash");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            //现金
            LambdaQueryWrapper<UserTransaction> queryWrapper = getUserTransactionLambdaQueryWrapper(3, now);
            List<UserTransaction> userTransactionList = userTransactionMapper.selectList(queryWrapper);
            //生成交易流水账单
            AtomicInteger index = new AtomicInteger(1);
            List<BillExcelVO> billExcelList = getBillExcelVOList(userTransactionList, index);
            UserBill userBill = insertBill(3, now);
            //获取excel oss地址
            String path = getExcel(2, billExcelList, getFileName(3, now), getTitName(3, now), getFileName(3, now), null, now.withDayOfMonth(1).minusMonths(1));
            log.info("现金账单path：{}", path);
            userBill.setFilePath(path);
            userBillMapper.updateById(userBill);
            return Boolean.TRUE;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }


    }

    @Override
    public boolean insertCardAll(LocalDateTime now) {


        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertCardAll");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            Map<String, LocalDateTime> billTimeMap = getBillTimeMap(now);
            LocalDateTime localDateBegin = billTimeMap.get("begin");
            LocalDateTime localDateEnd = billTimeMap.get("end");

            List<UserTransactionGroupByTimeVO> userTransactionList = userTransactionMapper.getUserIdGroupByEndTime(localDateEnd);
            List<SysUser> userList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                    .eq(SysUser::getDelFlag, 0)
                    .eq(SysUser::getIsAdmin, 1));
            List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoService.list();
            List<UserGeneralVO> userGeneralVOList = new ArrayList<>();
            AtomicInteger index = new AtomicInteger(1);
            for (SysUser a : userList) {
                if (a == null) {
                    continue;
                }

                if (StrUtil.isBlank(a.getGuid())) {
                    continue;
                }

                if (a.getUserId() == null) {
                    continue;
                }

                UserGeneralVO userGeneralVO = new UserGeneralVO();
                BeanUtil.copyProperties(a, userGeneralVO);
                userGeneralVO.setIndex(index.getAndIncrement());
                userGeneralVO.setUserTypeName(UserTypeToNameUtil.getUserType(a.getUserType()));
                userGeneralVO.setCardAccount(BigDecimal.ZERO);
                userGeneralVO.setCashAccount(BigDecimal.ZERO);
                userGeneralVO.setCardState(a.getCardState().equals("1") ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
                userGeneralVO.setCashState(a.getCashState().equals("1") ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
                if (!userDepartmentInfoList.isEmpty() && a.getCompanyId() != null) {
                    userDepartmentInfoList.stream().filter(Objects::nonNull)
                            .filter(b -> Objects.equals(a.getCompanyId(), b.getId()))
                            .findAny().ifPresent(userDepartmentInfo -> userGeneralVO.setCompanyName(userDepartmentInfo.getOrgShortName()));
                }
                if (!userTransactionList.isEmpty()) {
                    UserTransactionGroupByTimeVO userTransaction = userTransactionList.stream().filter(Objects::nonNull).filter(b -> Objects.equals(a.getUserId(), b.getUserId()))
                            .findFirst().orElse(null);

                    if (userTransaction != null) {
                        userGeneralVO.setCardAccount(userTransaction.getCardAccount() != null ? userTransaction.getCardAccount() : BigDecimal.ZERO);
                        userGeneralVO.setCashAccount(userTransaction.getCashAccount() != null ? userTransaction.getCashAccount() : BigDecimal.ZERO);
                    } else {
                        userGeneralVO.setCardAccount(BigDecimal.ZERO);
                        userGeneralVO.setCashAccount(BigDecimal.ZERO);
                    }
                }
                userGeneralVOList.add(userGeneralVO);
            }
            UserBill userBill = insertBill(5, now);
            userBill.setFilePath(getCardAllExcel(userGeneralVOList, localDateBegin));
            userBillMapper.updateById(userBill);
            return Boolean.TRUE;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    public static BigDecimal getFilterList(List<TransactionGroupUserIdVO> businessUserIdCard, Integer type, String guid) {
        List<TransactionGroupUserIdVO> returnList = businessUserIdCard.stream().filter(Objects::nonNull)
                .filter(v -> StrUtil.isNotBlank(v.getGuid())).filter(a -> Objects.equals(guid, a.getGuid()))
                .filter(a -> Objects.equals(type, a.getTransactionCategory())).toList();

        if (returnList.isEmpty()) {
            return BigDecimal.ZERO;
        }

        TransactionGroupUserIdVO transactionGroupUserIdVO = returnList.stream().findFirst().get();

        return transactionGroupUserIdVO.getTotal();
    }

    @Override
    public boolean insertBusinessAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertBusinessAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            //业务账单-汇总表
            //获取上个月第一天
            Map<String, LocalDateTime> billTimeMap = getBillTimeMap(now);
            LocalDateTime localDateBegin = billTimeMap.get("begin");
            LocalDateTime lastMomentOfLastMonth = billTimeMap.get("end");
            log.info("业务账单结束时间 >>>> time:{}", lastMomentOfLastMonth);
            //获取
            LambdaQueryWrapper<UserTransaction> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.ge(UserTransaction::getTransactionTime, localDateBegin)
                    .le(UserTransaction::getTransactionTime, lastMomentOfLastMonth);
            List<UserTransaction> userTransactionList = userTransactionMapper.selectList(queryWrapper);
            log.info("业务账单报表生成userTransactionList生成 >>>> userTransactionList:{}", userTransactionList);

            //账单周期
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String beginTime = localDateBegin.format(formatter);

            LocalDate lastDayOfPreviousMonth = now.toLocalDate()
                    // 调整为本月第一天
                    .with(TemporalAdjusters.firstDayOfMonth())
                    // 减去一天，即上个月最后一天
                    .minusDays(1);

            // 如果你想要的是最后一天的开始时刻（00:00）
            LocalDateTime startOfDayLastDay = lastDayOfPreviousMonth.atStartOfDay();
            String endTime = startOfDayLastDay.format(formatter);
            String businessCycle = beginTime + "-" + endTime;
            List<BusinessExcelVO> businessExcelVOList = new ArrayList<>();
            BusinessExcelVO businessExcelOneVO = new BusinessExcelVO();
            businessExcelOneVO.setIndex(1);
            businessExcelOneVO.setBusinessCycle(businessCycle);
            businessExcelOneVO.setAccountTypeName("餐补账户");
            //期初值 餐卡
            List<BusinessCardExcelVO> businessCardExcelVOList = new ArrayList<>();
            List<BusinessCardExcelVO> businessCashExcelVOList = new ArrayList<>();


            List<UserTransactionGroupByTimeVO> groupByBeginTime = userTransactionMapper.getUserIdGroupByBeginTime(localDateBegin);
            Map<Long, UserTransactionGroupByTimeVO> userIdBeginMap = groupByBeginTime.stream().collect(Collectors.toMap(UserTransactionGroupByTimeVO::getUserId, a -> a));
            List<UserTransactionGroupByTimeVO> groupByEndTime = userTransactionMapper.getUserIdGroupByEndTime(lastMomentOfLastMonth);
            Map<Long, UserTransactionGroupByTimeVO> userIdEndMap = groupByEndTime.stream().collect(Collectors.toMap(UserTransactionGroupByTimeVO::getUserId, a -> a));
            List<SysUser> sysUserList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                    .eq(SysUser::getIsAdmin, 1));

            List<TransactionGroupUserIdVO> businessUserIdCard = userTransactionMapper.getBusinessUserId(localDateBegin, lastMomentOfLastMonth, "1");
            List<TransactionGroupUserIdVO> businessUserIdCash = userTransactionMapper.getBusinessUserId(localDateBegin, lastMomentOfLastMonth, "2");
            int index = 1;
            for (SysUser sysUser : sysUserList) {

                if (sysUser == null) {
                    continue;
                }
                BusinessCardExcelVO businessCardExcelVO = new BusinessCardExcelVO();
                BusinessCardExcelVO businessCashExcelVO = new BusinessCardExcelVO();
                businessCardExcelVO.setIndex(index);
                businessCashExcelVO.setIndex(index);
                businessCardExcelVO.setGuid(sysUser.getGuid());
                businessCashExcelVO.setGuid(sysUser.getGuid());
                businessCardExcelVO.setUsername(sysUser.getUsername());
                businessCashExcelVO.setUsername(sysUser.getUsername());
                businessCardExcelVO.setUserJobNumber(sysUser.getUserJobNumber());
                businessCashExcelVO.setUserJobNumber(sysUser.getUserJobNumber());
                businessCardExcelVO.setPhone(sysUser.getPhone());
                businessCashExcelVO.setPhone(sysUser.getPhone());
                businessCardExcelVO.setAccountTypeName("餐补账户");
                businessCashExcelVO.setAccountTypeName("现金账户");
                UserTransactionGroupByTimeVO groupByTimeBeginVO = userIdBeginMap.get(sysUser.getUserId());
                UserTransactionGroupByTimeVO groupByTimeEndVO = userIdEndMap.get(sysUser.getUserId());
                businessCardExcelVO.setBeginBalance(groupByTimeBeginVO != null ? groupByTimeBeginVO.getCardAccount() : BigDecimal.ZERO);
                businessCashExcelVO.setBeginBalance(groupByTimeBeginVO != null ? groupByTimeBeginVO.getCashAccount() : BigDecimal.ZERO);
                businessCardExcelVO.setMkbRecharge(getFilterList(businessUserIdCard, 1, sysUser.getGuid()));
                businessCashExcelVO.setMkbRecharge(getFilterList(businessUserIdCash, 1, sysUser.getGuid()));
                businessCardExcelVO.setAccountRecharge(getFilterList(businessUserIdCard, 6, sysUser.getGuid()));
                businessCashExcelVO.setAccountRecharge(getFilterList(businessUserIdCash, 6, sysUser.getGuid()));
                businessCardExcelVO.setMkbConsume(getFilterList(businessUserIdCard, 2, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCard, 3, sysUser.getGuid())));
                businessCashExcelVO.setMkbConsume(getFilterList(businessUserIdCash, 2, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCash, 3, sysUser.getGuid())));
                businessCardExcelVO.setJdConsume(getFilterList(businessUserIdCard, 4, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCard, 5, sysUser.getGuid())));
                businessCashExcelVO.setJdConsume(getFilterList(businessUserIdCash, 4, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCash, 5, sysUser.getGuid())));
                businessCardExcelVO.setHdConsume(getFilterList(businessUserIdCard, 7, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCard, 8, sysUser.getGuid())));
                businessCashExcelVO.setHdConsume(getFilterList(businessUserIdCash, 7, sysUser.getGuid())
                        .subtract(getFilterList(businessUserIdCash, 8, sysUser.getGuid())));
                //后台扣款
                businessCardExcelVO.setAccountPayment(getFilterList(businessUserIdCard, 10, sysUser.getGuid()));
                businessCashExcelVO.setAccountPayment(getFilterList(businessUserIdCash, 10, sysUser.getGuid()));
                businessCardExcelVO.setEndBalance(groupByTimeEndVO != null ? groupByTimeEndVO.getCardAccount() : BigDecimal.ZERO);
                businessCashExcelVO.setEndBalance(groupByTimeEndVO != null ? groupByTimeEndVO.getCashAccount() : BigDecimal.ZERO);

                businessCardExcelVOList.add(businessCardExcelVO);
                businessCashExcelVOList.add(businessCashExcelVO);
                index++;
            }

            //餐卡
            Map<Integer, BigDecimal> businessToCardMap = UserTypeToNameUtil.getMapToBig(userTransactionMapper.getBusinessTo(localDateBegin, lastMomentOfLastMonth, "1")
                    .stream().filter(Objects::nonNull).collect(Collectors.toMap(TransactionGroupVO::getTransactionCategory, a -> a)));
            businessExcelOneVO.setBeginBalance(groupByBeginTime.stream()
                    .filter(Objects::nonNull)
                    .map(UserTransactionGroupByTimeVO::getCardAccount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            businessExcelOneVO.setMkbRecharge(businessToCardMap.get(1));
            businessExcelOneVO.setAccountRecharge(businessToCardMap.get(6));
            businessExcelOneVO.setAccountPayment(businessToCardMap.get(10));
            businessExcelOneVO.setMkbConsume(businessToCardMap.get(2).subtract(businessToCardMap.get(3)));
            businessExcelOneVO.setJdConsume(businessToCardMap.get(4).subtract(businessToCardMap.get(5)));
            businessExcelOneVO.setHdConsume(businessToCardMap.get(7).subtract(businessToCardMap.get(8)));
            businessExcelOneVO.setEndBalance(groupByEndTime.stream().filter(Objects::nonNull)
                    .map(UserTransactionGroupByTimeVO::getCardAccount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            businessExcelVOList.add(businessExcelOneVO);
            Map<Integer, BigDecimal> businessToCashMap = UserTypeToNameUtil.getMapToBig(userTransactionMapper.getBusinessTo(localDateBegin, lastMomentOfLastMonth, "2").stream()
                    .filter(Objects::nonNull).collect(Collectors.toMap(TransactionGroupVO::getTransactionCategory, a -> a)));
            BusinessExcelVO businessExcelTwoVO = new BusinessExcelVO();
            businessExcelTwoVO.setIndex(2);
            businessExcelTwoVO.setBusinessCycle(businessCycle);
            businessExcelTwoVO.setAccountTypeName("现金账户");
            businessExcelTwoVO.setBeginBalance(groupByBeginTime.stream()
                    .filter(Objects::nonNull)
                    .map(UserTransactionGroupByTimeVO::getCashAccount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            businessExcelTwoVO.setMkbRecharge(businessToCashMap.get(1));
            businessExcelTwoVO.setAccountRecharge(businessToCashMap.get(6));
            businessExcelTwoVO.setAccountPayment(businessToCashMap.get(10));
            businessExcelTwoVO.setMkbConsume(businessToCashMap.get(2).subtract(businessToCashMap.get(3)));
            businessExcelTwoVO.setJdConsume(businessToCashMap.get(4).subtract(businessToCashMap.get(5)));
            businessExcelTwoVO.setHdConsume(businessToCashMap.get(7).subtract(businessToCashMap.get(8)));
            businessExcelTwoVO.setEndBalance(groupByEndTime.stream()
                    .filter(Objects::nonNull)
                    .map(UserTransactionGroupByTimeVO::getCashAccount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            businessExcelVOList.add(businessExcelTwoVO);
            BusinessExcelVO businessExcelThreeVO = new BusinessExcelVO();
            businessExcelThreeVO.setIndex(3);
            businessExcelThreeVO.setBusinessCycle("合计");
            businessExcelThreeVO.setAccountTypeName("-");
            businessExcelThreeVO.setAccountPayment(businessExcelOneVO.getAccountPayment().add(businessExcelTwoVO.getAccountPayment()));
            businessExcelThreeVO.setBeginBalance(businessExcelOneVO.getBeginBalance().add(businessExcelTwoVO.getBeginBalance()));
            businessExcelThreeVO.setMkbRecharge(businessExcelOneVO.getMkbRecharge().add(businessExcelTwoVO.getMkbRecharge()));
            businessExcelThreeVO.setAccountRecharge(businessExcelOneVO.getAccountRecharge().add(businessExcelTwoVO.getAccountRecharge()));
            businessExcelThreeVO.setMkbConsume(businessExcelOneVO.getMkbConsume().add(businessExcelTwoVO.getMkbConsume()));
            businessExcelThreeVO.setJdConsume(businessExcelOneVO.getJdConsume().add(businessExcelTwoVO.getJdConsume()));
            businessExcelThreeVO.setHdConsume(businessExcelOneVO.getHdConsume().add(businessExcelTwoVO.getHdConsume()));
            businessExcelThreeVO.setEndBalance(businessExcelOneVO.getEndBalance().add(businessExcelTwoVO.getEndBalance()));
            businessExcelVOList.add(businessExcelThreeVO);


//        生成账单 生成excel文档
            String bucketName = minioUtil.getBucketName();
            ExportParams exportParamBusinessOne = new ExportParams("业务账单-汇总表", "业务账单-汇总表", ExcelType.HSSF);
            Map<String, Object> paramsOneMap = new HashMap<>();
            paramsOneMap.put("title", exportParamBusinessOne);
            paramsOneMap.put("entity", BusinessExcelVO.class);
            paramsOneMap.put("data", businessExcelVOList);
            ExportParams exportParam2 = new ExportParams(localDateBegin.getMonthValue() + "月业务账单-餐补账户明细表", localDateBegin.getMonthValue() + "月业务账单-餐补账户明细表", ExcelType.HSSF);
            Map<String, Object> paramsTwoMap = new HashMap<>();
            paramsTwoMap.put("title", exportParam2);
            paramsTwoMap.put("entity", BusinessCardExcelVO.class);
            paramsTwoMap.put("data", businessCardExcelVOList);
            ExportParams exportParam3 = new ExportParams(localDateBegin.getMonthValue() + "月业务账单-现金账户明细表", localDateBegin.getMonthValue() + "月业务账单-现金账户明细表", ExcelType.HSSF);
            Map<String, Object> paramsThreeMap = new HashMap<>();
            paramsThreeMap.put("title", exportParam3);
            paramsThreeMap.put("entity", BusinessCardExcelVO.class);
            paramsThreeMap.put("data", businessCashExcelVOList);
            // 将2个sheet封装
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            sheetsList.add(paramsOneMap);
            sheetsList.add(paramsTwoMap);
            sheetsList.add(paramsThreeMap);
            Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
            log.info("业务账单-汇总表生成 >>>> workbook:{}", workbook);
            String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", localDateBegin.getMonthValue() + "月业务账单-汇总表" + XLSX, false);
            UserBill userBill = new UserBill();
            // 获取上个月的年份和月份
            int year = localDateBegin.getYear();
            int month = localDateBegin.getMonthValue();
            userBill.setBillTime(year + "-" + month);
            userBill.setFilePath(path);
            userBill.setBillType(6);
            userBill.setCreateTime(LocalDateTime.now());
            userBill.setBillName(year + "年" + month + "月账户业务对账单");
            userBillMapper.deleteBill(year + "-" + month, 6);
            userBillMapper.insert(userBill);
            return Boolean.TRUE;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertMKBRechargeAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertMKBRechargeAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertRechargePublic(1, 1, now);

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertAccountPay(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertAccountPay");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertRechargePublic(1, 3, now);

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }


    /**
     * 满客宝京东好点消费账单 每天生成 T+1
     *
     * @param type 1为满客宝消费账单 2 为京东消费账单 3 为好点消费账单
     * @param time 1为月  2为日
     * @return
     */
    public boolean insertPayAccount(int time, int type, LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertPayAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            // 获取当前日期
            UserBill userBill = new UserBill();

            LocalDateTime beginTime = null;
            LocalDateTime endTime = null;

            // 定义日期格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            if (time == 1) {
                //按月生成

                //获取上个月第一天
                LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);
                beginTime = firstDayOfLastMonth.withHour(0).withMinute(0).withSecond(0).withNano(0);
                // 获取当天凌晨时间
                // 获取上个月的最后一天
                LocalDateTime lastDayOfLastMonth = now.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
                // 设置时间为23:59:59
                endTime = lastDayOfLastMonth.withHour(23).withMinute(59).withSecond(59);

            } else if (time == 2) {
                //按日生成
                beginTime = LocalDateTime.of(now.toLocalDate(), LocalTime.MIDNIGHT);

                // 获取昨天的日期
                LocalDate yesterday = LocalDate.now().minusDays(1);
                endTime = LocalDateTime.of(yesterday, LocalTime.MIDNIGHT);
                // 将昨天的日期格式化为字符串
            }

            // 获取上个月的年份和月份
            assert beginTime != null;
            int year = beginTime.getYear();
            int month = beginTime.getMonthValue();
            userBill.setBillTime(year + "-" + month);
            String yesterdayString = beginTime.format(formatter) + "-" + endTime.format(formatter);

            // 查询昨天所有消费记录
            if (type == 1) {
                userBill.setBillType(9);
                userBill.setBillName(year + "年" + month + "月满客宝消费账单");

            } else if (type == 2) {
                userBill.setBillType(10);
                userBill.setBillName(year + "年" + month + "月京东消费账单");
            } else if (type == 3) {
                userBill.setBillType(11);
                userBill.setBillName(year + "年" + month + "月轨道生活通消费账单");
            }

            List<ConsumeBillExcelVO> consumeBillExcelVOList = new ArrayList<>();
            List<PaymentBillExcelVO> paymentBillExcelVOList = new ArrayList<>();
            List<DeductionBillExcelVO> deductionBillExcelVOList = new ArrayList<>();

            ConsumeBillExcelVO consumeOneVO = new ConsumeBillExcelVO();
            ConsumeBillExcelVO consumeTwoVO = new ConsumeBillExcelVO();
            ConsumeBillExcelVO consumeThreeVO = new ConsumeBillExcelVO();

            if (type == 1) {
                paymentBillExcelVOList = userTransactionMapper.getPayment("满客宝", "2", beginTime, endTime);
                deductionBillExcelVOList = userTransactionMapper.getDeduction("满客宝", "3", beginTime, endTime);
            } else if (type == 2) {
                paymentBillExcelVOList = userTransactionMapper.getPayment("京东", "4", beginTime, endTime);
                deductionBillExcelVOList = userTransactionMapper.getDeduction("京东", "5", beginTime, endTime);
            } else if (type == 3) {
                paymentBillExcelVOList = userTransactionMapper.getPayment("生活通", "7", beginTime, endTime);
                deductionBillExcelVOList = userTransactionMapper.getDeduction("生活通", "8", beginTime, endTime);
            }

            if (!deductionBillExcelVOList.isEmpty()) {

                for (DeductionBillExcelVO deductionBillExcelVO : deductionBillExcelVOList) {

                    if (deductionBillExcelVO == null) {
                        continue;
                    }

                    if (StrUtil.isBlank(deductionBillExcelVO.getAccountCenterOrderNumber())) {
                        continue;
                    }

                    UserTransaction userTransaction = userTransactionMapper.selectOne(Wrappers.<UserTransaction>lambdaQuery()
                            .eq(UserTransaction::getOrderId, deductionBillExcelVO.getAccountCenterOrderNumber())
                            .in(UserTransaction::getTransactionType, "2", "4", "7")
                            .eq(StrUtil.isNotBlank(deductionBillExcelVO.getAccountType()), UserTransaction::getAccountType, deductionBillExcelVO.getAccountType().equals("现金账户") ? "2" : "1")
                            .last(" limit 1"));

                    if (userTransaction != null) {
                        deductionBillExcelVO.setAccountCenterPaymentSerialNumber(StrUtil.isNotBlank(userTransaction.getRechargeStream()) ? userTransaction.getRechargeStream() : null);
                        deductionBillExcelVO.setThirdPartyPaymentSerialNumber(StrUtil.isNotBlank(userTransaction.getThirdRechargeStream()) ? userTransaction.getThirdRechargeStream() : null);
                        deductionBillExcelVO.setPaymentTime(userTransaction.getTransactionTime() != null ? userTransaction.getTransactionTime() : null);
                        deductionBillExcelVO.setAmount(userTransaction.getTransactionNumber() != null ? userTransaction.getTransactionNumber() : BigDecimal.ZERO);
                    }
                }
            }

            consumeOneVO.setIndex(1);
            consumeOneVO.setBillingCycle(yesterdayString);
            consumeOneVO.setAccountType("餐补账户");
            consumeOneVO.setPaymentCount(paymentBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "餐补账户".equals(a.getAccountType())).toList().size());
            consumeOneVO.setPaymentAmount(paymentBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "餐补账户".equals(a.getAccountType())).map(PaymentBillExcelVO::getPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            consumeOneVO.setRefundCount(deductionBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "餐补账户".equals(a.getAccountType())).toList().size());
            consumeOneVO.setRefundAmount(deductionBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "餐补账户".equals(a.getAccountType())).map(DeductionBillExcelVO::getRefundAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));

            consumeTwoVO.setIndex(2);
            consumeTwoVO.setBillingCycle(yesterdayString);
            consumeTwoVO.setAccountType("现金账户");
            consumeTwoVO.setPaymentCount(paymentBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "现金账户".equals(a.getAccountType())).toList().size());
            consumeTwoVO.setPaymentAmount(paymentBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "现金账户".equals(a.getAccountType())).map(PaymentBillExcelVO::getPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            consumeTwoVO.setRefundCount(deductionBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "现金账户".equals(a.getAccountType())).toList().size());
            consumeTwoVO.setRefundAmount(deductionBillExcelVOList.stream().filter(Objects::nonNull)
                    .filter(a -> "现金账户".equals(a.getAccountType())).map(DeductionBillExcelVO::getRefundAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));

            consumeThreeVO.setIndex(3);
            consumeThreeVO.setBillingCycle("合计");
            consumeThreeVO.setAccountType("-");
            consumeThreeVO.setPaymentCount(consumeOneVO.getPaymentCount() + consumeTwoVO.getPaymentCount());
            consumeThreeVO.setPaymentAmount(consumeOneVO.getPaymentAmount().add(consumeTwoVO.getPaymentAmount()));
            consumeThreeVO.setRefundCount(consumeOneVO.getRefundCount() + consumeTwoVO.getRefundCount());
            consumeThreeVO.setRefundAmount(consumeOneVO.getRefundAmount().add(consumeTwoVO.getRefundAmount()));

            consumeOneVO.setNetTransactionAmount(consumeOneVO.getPaymentAmount().subtract(consumeOneVO.getRefundAmount()));
            consumeTwoVO.setNetTransactionAmount(consumeTwoVO.getPaymentAmount().subtract(consumeTwoVO.getRefundAmount()));
            consumeThreeVO.setNetTransactionAmount(consumeOneVO.getNetTransactionAmount().add(consumeTwoVO.getNetTransactionAmount()));
            consumeBillExcelVOList.add(consumeOneVO);
            consumeBillExcelVOList.add(consumeTwoVO);
            consumeBillExcelVOList.add(consumeThreeVO);

            Map<Integer, String> typeNameMap = channelName(type);
            //生成账单 生成excel文档
            String bucketName = minioUtil.getBucketName();
            ExportParams exportParamBusinessOne = new ExportParams(typeNameMap.get(1), typeNameMap.get(1), ExcelType.HSSF);
            Map<String, Object> paramsOneMap = new HashMap<>();
            paramsOneMap.put("title", exportParamBusinessOne);
            paramsOneMap.put("entity", ConsumeBillExcelVO.class);
            paramsOneMap.put("data", consumeBillExcelVOList);
            ExportParams exportParam2 = new ExportParams(typeNameMap.get(2), typeNameMap.get(2), ExcelType.HSSF);
            Map<String, Object> paramsTwoMap = new HashMap<>();
            paramsTwoMap.put("title", exportParam2);
            paramsTwoMap.put("entity", PaymentBillExcelVO.class);
            paramsTwoMap.put("data", paymentBillExcelVOList);
            ExportParams exportParam3 = new ExportParams(typeNameMap.get(3), typeNameMap.get(3), ExcelType.HSSF);
            Map<String, Object> paramsThreeMap = new HashMap<>();
            paramsThreeMap.put("title", exportParam3);
            paramsThreeMap.put("entity", DeductionBillExcelVO.class);
            paramsThreeMap.put("data", deductionBillExcelVOList);
            // 将2个sheet封装
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            sheetsList.add(paramsOneMap);
            sheetsList.add(paramsTwoMap);
            sheetsList.add(paramsThreeMap);
            Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
            log.info("满客宝消费月账单-汇总表 >>>> workbook:{}", workbook);
            String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", beginTime.getMonthValue() + "月满客宝消费月账单-汇总表" + XLSX, false);
            userBill.setFilePath(path);
            userBill.setCreateTime(LocalDateTime.now());
            userBillMapper.deleteBill(year + "-" + month, userBill.getBillType());
            userBillMapper.insert(userBill);

            return Boolean.TRUE;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }


    }

    private static LocalDateTime setCreateTime() {
        LocalDateTime now = LocalDateTime.now();

        // 获取上个月的最后一天
        LocalDateTime lastDayOfLastMonth = now.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());

        // 设置时间为23:59:59
        return lastDayOfLastMonth.withHour(23).withMinute(59).withSecond(59);
    }

    /**
     * 1为餐补 2为现金
     *
     * @param type
     */
    public BigDecimal mkbRechargeAll(List<UserTransaction> userTransactionList, String type) {
        return userTransactionList.stream().filter(Objects::nonNull).filter(a -> type.equals(a.getAccountType()))
                .filter(a -> "1".equals(a.getTransactionType())).map(UserTransaction::getTransactionNumber)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }


    public Map<Integer, String> channelName(int type) {

        Map<Integer, String> map = new HashMap<>();
        String name = "";
        if (type == 1) {
            name = "满客宝";
        } else if (type == 2) {
            name = "京东";
        } else if (type == 3) {
            name = "轨道生活通";
        }
        map.put(1, name + "消费月账单-汇总表");
        map.put(2, name + "支付流水明细");
        map.put(3, name + "退款流水明细");
        return map;
    }


    /**
     * 满客宝后台充值账单  每天生成 T+1
     *
     * @param type 1 为满客宝充值账单 2 为后台充值账单 3为后台扣款账单
     * @param time 1 为按月生成  2为按日生成
     */
    public boolean insertRechargePublic(int time, int type, LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertRechargePublic");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            // 获取当前日期
            List<UserTransaction> allTransactionList = new ArrayList<>();
            String yesterdayString = "";
            LocalDateTime beginTime = null;
            LocalDateTime endTime = null;


            // 定义日期格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            if (time == 1) {
                //按月生成
                //获取上个月第一天
                LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);
                beginTime = firstDayOfLastMonth.withHour(0).withMinute(0).withSecond(0).withNano(0);
                // 获取当天凌晨时间
                // 获取上个月的最后一天
                LocalDateTime lastDayOfLastMonth = now.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
                // 设置时间为23:59:59
                endTime = lastDayOfLastMonth.withHour(23).withMinute(59).withSecond(59);
                // 将昨天的日期格式化为字符串
                yesterdayString = beginTime.format(formatter) + "-" + endTime.format(formatter);

            } else if (time == 2) {
                //按日生成
                beginTime = LocalDateTime.of(now.toLocalDate(), LocalTime.MIDNIGHT);
                // 获取昨天的日期
                LocalDate yesterday = LocalDate.now().minusDays(1);
                endTime = LocalDateTime.of(yesterday, LocalTime.MIDNIGHT);
                // 将昨天的日期格式化为字符串
                yesterdayString = beginTime.format(formatter) + "-" + endTime.format(formatter);
            }

            // 获取上个月的年份和月份
            assert beginTime != null;
            int year = beginTime.getYear();
            int month = beginTime.getMonthValue();

            if (type == 1) {
                allTransactionList = userTransactionMapper.selectList(Wrappers.<UserTransaction>lambdaQuery()
                        .ge(UserTransaction::getTransactionTime, beginTime)
                        .lt(UserTransaction::getTransactionTime, endTime)
                        .eq(UserTransaction::getTransactionType, "1"));
            } else if (type == 2) {
                allTransactionList = userTransactionMapper.selectList(Wrappers.<UserTransaction>lambdaQuery()
                        .ge(UserTransaction::getTransactionTime, beginTime)
                        .lt(UserTransaction::getTransactionTime, endTime)
                        .eq(UserTransaction::getTransactionType, "6"));
            } else if (type == 3) {
                allTransactionList = userTransactionMapper.selectList(Wrappers.<UserTransaction>lambdaQuery()
                        .ge(UserTransaction::getTransactionTime, beginTime)
                        .lt(UserTransaction::getTransactionTime, endTime)
                        .eq(UserTransaction::getTransactionType, "10"));
            }

            List<MKBRechargeExcelVO> mkbRechargeExcelVOList = new ArrayList<>();
            List<AccountPayExcelVO> accountPayExcelVOList = new ArrayList<>();

            if (type != 3) {
                MKBRechargeExcelVO rechargeOneVO = new MKBRechargeExcelVO();
                rechargeOneVO.setIndex(1);
                rechargeOneVO.setBusinessCycle(yesterdayString);
                rechargeOneVO.setAccountTypeName("餐补账户");
                rechargeOneVO.setRechargeSize(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "1".equals(a.getAccountType())).toList().size());
                rechargeOneVO.setRechargeAmount(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "1".equals(a.getAccountType())).map(UserTransaction::getTransactionNumber).reduce(BigDecimal.ZERO, BigDecimal::add));
                MKBRechargeExcelVO rechargeTwoVO = new MKBRechargeExcelVO();
                rechargeTwoVO.setIndex(2);
                rechargeTwoVO.setBusinessCycle(yesterdayString);
                rechargeTwoVO.setAccountTypeName("现金账户");
                rechargeTwoVO.setRechargeSize(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "2".equals(a.getAccountType())).toList().size());
                rechargeTwoVO.setRechargeAmount(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "2".equals(a.getAccountType())).map(UserTransaction::getTransactionNumber).reduce(BigDecimal.ZERO, BigDecimal::add));
                MKBRechargeExcelVO rechargeThreeVO = new MKBRechargeExcelVO();
                rechargeThreeVO.setIndex(3);
                rechargeThreeVO.setBusinessCycle("合计");
                rechargeThreeVO.setAccountTypeName("-");
                rechargeThreeVO.setRechargeSize(rechargeOneVO.getRechargeSize() + rechargeTwoVO.getRechargeSize());
                rechargeThreeVO.setRechargeAmount(rechargeOneVO.getRechargeAmount().add(rechargeTwoVO.getRechargeAmount()));
                mkbRechargeExcelVOList.add(rechargeOneVO);
                mkbRechargeExcelVOList.add(rechargeTwoVO);
                mkbRechargeExcelVOList.add(rechargeThreeVO);
            } else {
                AccountPayExcelVO rechargeOneVO = new AccountPayExcelVO();
                rechargeOneVO.setIndex(1);
                rechargeOneVO.setBusinessCycle(yesterdayString);
                rechargeOneVO.setAccountTypeName("餐补账户");
                rechargeOneVO.setRechargeSize(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "1".equals(a.getAccountType())).toList().size());
                rechargeOneVO.setRechargeAmount(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "1".equals(a.getAccountType())).map(UserTransaction::getTransactionNumber)
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                AccountPayExcelVO rechargeTwoVO = new AccountPayExcelVO();
                rechargeTwoVO.setIndex(2);
                rechargeTwoVO.setBusinessCycle(yesterdayString);
                rechargeTwoVO.setAccountTypeName("现金账户");
                rechargeTwoVO.setRechargeSize(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "2".equals(a.getAccountType())).toList().size());
                rechargeTwoVO.setRechargeAmount(allTransactionList.stream().filter(Objects::nonNull)
                        .filter(a -> "2".equals(a.getAccountType())).map(UserTransaction::getTransactionNumber)
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                AccountPayExcelVO rechargeThreeVO = new AccountPayExcelVO();
                rechargeThreeVO.setIndex(3);
                rechargeThreeVO.setBusinessCycle("合计");
                rechargeThreeVO.setAccountTypeName("-");
                rechargeThreeVO.setRechargeSize(rechargeOneVO.getRechargeSize() + rechargeTwoVO.getRechargeSize());
                rechargeThreeVO.setRechargeAmount(rechargeOneVO.getRechargeAmount().add(rechargeTwoVO.getRechargeAmount()));
                accountPayExcelVOList.add(rechargeOneVO);
                accountPayExcelVOList.add(rechargeTwoVO);
                accountPayExcelVOList.add(rechargeThreeVO);
            }

            List<MKBRechargeInfoExcelVO> mkbRechargeInfoExcelVOList = new ArrayList<>();
            //后台充值
            List<RechargeInfoExcelVO> rechargeInfoExcelVOList = new ArrayList<>();
            List<AccountPayInfoExcelVO> accountPayInfoExcelVOList = new ArrayList<>();
            int index = 1;
            for (UserTransaction userTransaction : allTransactionList) {
                if (userTransaction == null) {
                    continue;
                }

                if (StrUtil.isBlank(userTransaction.getAccountType())) {
                    continue;
                }

                if (type == 1) {
                    MKBRechargeInfoExcelVO mkbRechargeInfoExcelVO = new MKBRechargeInfoExcelVO();
                    mkbRechargeInfoExcelVO.setIndex(index);
                    mkbRechargeInfoExcelVO.setTransactionTime(userTransaction.getTransactionTime());
                    mkbRechargeInfoExcelVO.setTransactionTypeName(UserTypeToNameUtil.getTransactionType(userTransaction.getTransactionType()));
                    mkbRechargeInfoExcelVO.setAccountTypeName("1".equals(userTransaction.getAccountType()) ? "餐补账户" : "现金账户");
                    mkbRechargeInfoExcelVO.setRechargeAmount(userTransaction.getTransactionNumber());
                    mkbRechargeInfoExcelVO.setRechargeStream(userTransaction.getRechargeStream());
                    mkbRechargeInfoExcelVO.setThirdRechargeStream(userTransaction.getThirdRechargeStream());
                    mkbRechargeInfoExcelVO.setGuid(userTransaction.getGuid());
                    mkbRechargeInfoExcelVO.setUsername(userTransaction.getUsername());
                    mkbRechargeInfoExcelVO.setUserJobNumber(userTransaction.getUserJobNumber());
                    mkbRechargeInfoExcelVO.setPhone(userTransaction.getPhone());

                    mkbRechargeInfoExcelVOList.add(mkbRechargeInfoExcelVO);
                } else if (type == 2) {
                    RechargeInfoExcelVO mkbRechargeInfoExcelVO = new RechargeInfoExcelVO();
                    mkbRechargeInfoExcelVO.setIndex(index);
                    mkbRechargeInfoExcelVO.setTransactionTime(userTransaction.getTransactionTime());
                    mkbRechargeInfoExcelVO.setTransactionTypeName(UserTypeToNameUtil.getTransactionType(userTransaction.getTransactionType()));
                    mkbRechargeInfoExcelVO.setAccountTypeName("1".equals(userTransaction.getAccountType()) ? "餐补账户" : "现金账户");
                    mkbRechargeInfoExcelVO.setRechargeAmount(userTransaction.getTransactionNumber());
                    mkbRechargeInfoExcelVO.setRechargeStream(userTransaction.getRechargeStream());
                    mkbRechargeInfoExcelVO.setGuid(userTransaction.getGuid());
                    mkbRechargeInfoExcelVO.setUsername(userTransaction.getUsername());
                    mkbRechargeInfoExcelVO.setUserJobNumber(userTransaction.getUserJobNumber());
                    mkbRechargeInfoExcelVO.setPhone(userTransaction.getPhone());

                    rechargeInfoExcelVOList.add(mkbRechargeInfoExcelVO);
                } else {
                    AccountPayInfoExcelVO mkbRechargeInfoExcelVO = new AccountPayInfoExcelVO();
                    mkbRechargeInfoExcelVO.setIndex(index);
                    mkbRechargeInfoExcelVO.setTransactionTime(userTransaction.getTransactionTime());
                    mkbRechargeInfoExcelVO.setTransactionTypeName(UserTypeToNameUtil.getTransactionType(userTransaction.getTransactionType()));
                    mkbRechargeInfoExcelVO.setAccountTypeName("1".equals(userTransaction.getAccountType()) ? "餐补账户" : "现金账户");
                    mkbRechargeInfoExcelVO.setRechargeAmount(userTransaction.getTransactionNumber());
                    mkbRechargeInfoExcelVO.setRechargeStream(userTransaction.getRechargeStream());
                    mkbRechargeInfoExcelVO.setGuid(userTransaction.getGuid());
                    mkbRechargeInfoExcelVO.setUsername(userTransaction.getUsername());
                    mkbRechargeInfoExcelVO.setUserJobNumber(userTransaction.getUserJobNumber());
                    mkbRechargeInfoExcelVO.setPhone(userTransaction.getPhone());

                    accountPayInfoExcelVOList.add(mkbRechargeInfoExcelVO);
                }

                index++;
            }

            log.info("满客宝充值数据， {}", mkbRechargeInfoExcelVOList);
            log.info("后台充值， {}", rechargeInfoExcelVOList);
            log.info("后台扣费-数据, {}", accountPayInfoExcelVOList);

            //生成excel表
            String bucketName = minioUtil.getBucketName();
            UserBill userBill = new UserBill();
            if (type == 1) {
                ExportParams exportParamOne = new ExportParams("满客宝充值账单-汇总表", "满客宝充值账单-汇总表", ExcelType.HSSF);
                Map<String, Object> paramsOneMap = new HashMap<>();
                paramsOneMap.put("title", exportParamOne);
                paramsOneMap.put("entity", MKBRechargeExcelVO.class);
                paramsOneMap.put("data", mkbRechargeExcelVOList);
                ExportParams exportParam2 = new ExportParams("满客宝充值账单-明细表", "满客宝充值账单-明细表", ExcelType.HSSF);
                Map<String, Object> paramsTwoMap = new HashMap<>();
                paramsTwoMap.put("title", exportParam2);
                paramsTwoMap.put("entity", MKBRechargeInfoExcelVO.class);
                paramsTwoMap.put("data", mkbRechargeInfoExcelVOList);
                // 将2个sheet封装
                List<Map<String, Object>> sheetsList = new ArrayList<>();
                sheetsList.add(paramsOneMap);
                sheetsList.add(paramsTwoMap);
                Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
                log.info("满客宝充值账单-明细表生成 >>>> workbook:{}", workbook);
                String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", yesterdayString + "满客宝充值账单-明细表" + XLSX, false);
                userBill.setFilePath(path);
                userBill.setBillType(7);
                userBill.setBillName(year + "年" + month + "月满客宝充值账单");
            } else if (type == 2) {
                ExportParams exportParamOne = new ExportParams("后台充值账单-汇总表", "后台充值账单-汇总表", ExcelType.HSSF);
                Map<String, Object> paramsOneMap = new HashMap<>();
                paramsOneMap.put("title", exportParamOne);
                paramsOneMap.put("entity", MKBRechargeExcelVO.class);
                paramsOneMap.put("data", mkbRechargeExcelVOList);
                ExportParams exportParam2 = new ExportParams("后台充值账单-明细表", "后台充值账单-明细表", ExcelType.HSSF);
                Map<String, Object> paramsTwoMap = new HashMap<>();
                paramsTwoMap.put("title", exportParam2);
                paramsTwoMap.put("entity", RechargeInfoExcelVO.class);
                paramsTwoMap.put("data", rechargeInfoExcelVOList);
                // 将2个sheet封装
                List<Map<String, Object>> sheetsList = new ArrayList<>();
                sheetsList.add(paramsOneMap);
                sheetsList.add(paramsTwoMap);
                Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
                log.info("后台充值账单-明细表 >>>> workbook:{}", workbook);
                String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", yesterdayString + "后台充值账单-明细表" + XLSX, false);
                userBill.setFilePath(path);
                userBill.setBillType(8);
                userBill.setBillName(year + "年" + month + "月后台充值账单");
            } else if (type == 3) {
                ExportParams exportParamOne = new ExportParams("后台扣款账单-汇总表", "后台扣款账单-汇总表", ExcelType.HSSF);
                Map<String, Object> paramsOneMap = new HashMap<>();
                paramsOneMap.put("title", exportParamOne);
                paramsOneMap.put("entity", AccountPayExcelVO.class);
                paramsOneMap.put("data", accountPayExcelVOList);
                ExportParams exportParam2 = new ExportParams("后台扣款账单-明细表", "后台扣款账单-明细表", ExcelType.HSSF);
                Map<String, Object> paramsTwoMap = new HashMap<>();
                paramsTwoMap.put("title", exportParam2);
                paramsTwoMap.put("entity", AccountPayInfoExcelVO.class);
                paramsTwoMap.put("data", accountPayInfoExcelVOList);
                // 将2个sheet封装
                List<Map<String, Object>> sheetsList = new ArrayList<>();
                sheetsList.add(paramsOneMap);
                sheetsList.add(paramsTwoMap);
                Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
                log.info("后台扣款账单-明细表 >>>> workbook:{}", workbook);
                String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", yesterdayString + "后台扣款账单-明细表" + XLSX, false);
                userBill.setFilePath(path);
                userBill.setBillType(13);
                userBill.setBillName(year + "年" + month + "月后台扣款账单");
            }

            userBill.setBillTime(year + "-" + month);
            userBill.setCreateTime(LocalDateTime.now());
            userBillMapper.deleteBill(year + "-" + month, userBill.getBillType());
            userBillMapper.insert(userBill);
            return Boolean.TRUE;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }


    @Override
    public boolean insertBackend(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertBackend");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertRechargePublic(1, 2, now);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertJdBalanceAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertJdBalanceAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            UserBill userBill = new UserBill();
            userBill.setCreateTime(LocalDateTime.now());
            // 向前推移一个月
            //获取上个月第一天
            LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);
            LocalDateTime localDateBegin = firstDayOfLastMonth.withHour(0).withMinute(0).withSecond(0).withNano(0);
            log.info("京东结算开始时间 >>>> time:{}", localDateBegin);
            // 获取上个月的最后一天
            LocalDateTime lastDayOfLastMonth = now.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
            // 设置时间为23:59:59
            LocalDateTime localDateEnd = lastDayOfLastMonth.withHour(23).withMinute(59).withSecond(59);
            log.info("京东结算结束时间 >>>> time:{}", localDateEnd);
            // 获取上个月的年份和月份
            int year = firstDayOfLastMonth.getYear();
            int month = firstDayOfLastMonth.getMonthValue();
            userBill.setBillTime(year + "-" + month);
            userBill.setBillName(year + "年" + month + "月京东结算账单");
            userBill.setBillType(12);

            //账单周期
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String beginTime = localDateBegin.format(formatter);

            String endTime = localDateEnd.format(formatter);
            String businessCycle = beginTime + "-" + endTime;

            List<JdOrderSku> jdOrderSkuList = jdOrderSkuMapper.selectList(Wrappers.<JdOrderSku>lambdaQuery()
                    .ge(JdOrderSku::getCreateTime, localDateBegin)
                    .le(JdOrderSku::getCreateTime, localDateEnd));

            List<BillJDCycleExcelVO> billJDCycleExcelVOList = new ArrayList<>();
            for (JdOrderSku jdOrderSku : jdOrderSkuList) {

                if (jdOrderSku == null) {
                    continue;
                }

                if (jdOrderSku.getSkuId() == null) {
                    continue;
                }
                BillJDCycleExcelVO billJDCycleExcelVO = new BillJDCycleExcelVO();
                billJDCycleExcelVO.setBillCycle(businessCycle);
                billJDCycleExcelVO.setProductCode(jdOrderSku.getSkuId());
                billJDCycleExcelVO.setQuantity(jdOrderSku.getNum());
                billJDCycleExcelVO.setCostPrice(jdOrderSku.getPrice());
                billJDCycleExcelVO.setCostTotal(new BigDecimal(jdOrderSku.getNum()).multiply(jdOrderSku.getPrice()));
                billJDCycleExcelVO.setSalePrice(jdOrderSku.getBp() != null ? jdOrderSku.getBp() : BigDecimal.ZERO);
                billJDCycleExcelVO.setSaleTotal(new BigDecimal(jdOrderSku.getNum()).multiply(jdOrderSku.getBp()));

                billJDCycleExcelVOList.add(billJDCycleExcelVO);
            }

            //京东订单明细
            List<BillJDInfoExcelVO> jdOrderList = jdOrderMapper.getJDOrderList(localDateBegin, localDateEnd);

            log.info("京东订单明细: {}", JSON.toJSONString(jdOrderList));

            for (BillJDInfoExcelVO jdInfoExcelVO : jdOrderList) {
                if (jdInfoExcelVO == null) {
                    continue;
                }

                jdInfoExcelVO.setPaymentChannel("京东");

                if (StrUtil.isNotBlank(jdInfoExcelVO.getJdParentOrderId())) {
                    if (!jdOrderSkuList.isEmpty()) {
                        JdOrderSku jdOrderSku = jdOrderSkuList.stream()
                                .filter(jdOrderSku1 -> jdInfoExcelVO.getJdChildOrderId().equals(String.valueOf(jdOrderSku1.getOfOrderId())))
                                .findFirst().orElse(null);

                        if (jdOrderSku != null) {
                            jdInfoExcelVO.setProductCode(jdOrderSku.getSkuId() != null ? String.valueOf(jdOrderSku.getSkuId()) : "");
                            jdInfoExcelVO.setQuantity(jdOrderSku.getNum() != null ? jdOrderSku.getNum() : 0);
                            jdInfoExcelVO.setCostPrice(jdOrderSku.getPrice() != null ? jdOrderSku.getPrice() : BigDecimal.ZERO);
                            jdInfoExcelVO.setSaleTotal(jdInfoExcelVO.getSalePrice() != null ? jdInfoExcelVO.getSalePrice().multiply(new BigDecimal(jdInfoExcelVO.getQuantity())) : BigDecimal.ZERO);
                            jdInfoExcelVO.setCostTotal(jdInfoExcelVO.getCostPrice() != null ? jdInfoExcelVO.getCostPrice().multiply(new BigDecimal(jdInfoExcelVO.getQuantity())) : BigDecimal.ZERO);

                        }
                    }
                }
            }

            List<BillJDAfterSalesExcelVO> jdAfterSaleList = jdOrderMapper.getJDAfterSaleList(localDateBegin, localDateEnd);

            log.info("京东售后明细账单 数据：{}", JSON.toJSONString(jdAfterSaleList));

            List<UserOrderInfo> userOrderInfoList = userOrderInfoMapper.selectList(null);

            for (BillJDAfterSalesExcelVO billJDAfterSalesExcelVO : jdAfterSaleList) {

                if (billJDAfterSalesExcelVO == null) {
                    continue;
                }

                billJDAfterSalesExcelVO.setRefundChannel("京东");

                if (StrUtil.isNotBlank(billJDAfterSalesExcelVO.getJdChildOrderId())) {
                    BillJDInfoExcelVO billJDInfoExcelVO = jdOrderList.stream().filter(Objects::nonNull)
                            .filter(j -> billJDAfterSalesExcelVO.getJdChildOrderId().equals(j.getJdChildOrderId()))
                            .findFirst().orElse(null);

                    if (billJDInfoExcelVO != null) {
                        billJDAfterSalesExcelVO.setProductCode(StrUtil.isNotBlank(billJDInfoExcelVO.getProductCode()) ? billJDInfoExcelVO.getProductCode() : "");
                        billJDAfterSalesExcelVO.setCostPrice(billJDInfoExcelVO.getCostPrice() != null ? billJDInfoExcelVO.getCostPrice() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setCostTotal(billJDInfoExcelVO.getCostTotal() != null ? billJDInfoExcelVO.getCostTotal() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setSalePrice(billJDInfoExcelVO.getSalePrice() != null ? billJDInfoExcelVO.getSalePrice() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setSaleTotal(billJDInfoExcelVO.getSaleTotal() != null ? billJDInfoExcelVO.getSaleTotal() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setSalePrice(billJDInfoExcelVO.getSalePrice() != null ? billJDInfoExcelVO.getSalePrice() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setOrderStatus(StrUtil.isNotBlank(billJDInfoExcelVO.getOrderStatus()) ? billJDInfoExcelVO.getOrderStatus() : "");
                        billJDAfterSalesExcelVO.setAccountCenterOrderNo(StrUtil.isNotBlank(billJDInfoExcelVO.getAccountCenterOrder()) ? billJDInfoExcelVO.getAccountCenterOrder() : "");
                        billJDAfterSalesExcelVO.setOrderAmount(billJDInfoExcelVO.getOrderAmount() != null ? billJDInfoExcelVO.getOrderAmount() : BigDecimal.ZERO);
                        billJDAfterSalesExcelVO.setOrderCompleteTime(billJDInfoExcelVO.getOrderCompleteTime() != null ? billJDInfoExcelVO.getOrderCompleteTime() : null);

                        if (billJDAfterSalesExcelVO.getRefundOrderId() != null) {
                            BillJDAfterSalesExcelVO jdRefundList = jdOrderMapper.getJDRefundList(billJDAfterSalesExcelVO.getRefundOrderId());
                            if (jdRefundList != null) {
                                billJDAfterSalesExcelVO.setProductCode(StrUtil.isNotBlank(jdRefundList.getProductCode()) ? jdRefundList.getProductCode() : "");
                                billJDAfterSalesExcelVO.setReturnQuantity(jdRefundList.getReturnQuantity());
                            }
                        }

                        UserOrderInfo userOrderInfo = userOrderInfoList.stream().filter(Objects::nonNull)
                                .filter(order -> order.getOrderId().equals(billJDAfterSalesExcelVO.getAccountCenterOrderNo()))
                                .findFirst().orElse(null);

                        if (userOrderInfo != null) {
                            billJDAfterSalesExcelVO.setAccountCenterOrderNo(StrUtil.isNotBlank(userOrderInfo.getOrderId()) ? userOrderInfo.getOrderId() : "");
                            billJDAfterSalesExcelVO.setAccountCenterRefundTime(userOrderInfo.getRefundTime() != null ? userOrderInfo.getRefundTime() : null);
                            billJDAfterSalesExcelVO.setRefundAmount(userOrderInfo.getAllRefundAmount() != null ? userOrderInfo.getAllRefundAmount() : BigDecimal.ZERO);
                            billJDAfterSalesExcelVO.setGuid(StrUtil.isNotBlank(userOrderInfo.getGuid()) ? userOrderInfo.getGuid() : "");
                            billJDAfterSalesExcelVO.setUserName(StrUtil.isNotBlank(userOrderInfo.getUsername()) ? userOrderInfo.getUsername() : "");
                            billJDAfterSalesExcelVO.setEmployeeNumber(StrUtil.isNotBlank(userOrderInfo.getUserJobNumber()) ? userOrderInfo.getUserJobNumber() : "");
                            billJDAfterSalesExcelVO.setPhoneNumber(StrUtil.isNotBlank(userOrderInfo.getPhone()) ? userOrderInfo.getPhone() : "");
                            billJDAfterSalesExcelVO.setUserType(userOrderInfo.getUserType() != null ? UserTypeToNameUtil.getUserType(userOrderInfo.getUserType()) : null);

                        }
                    }
                }

            }

            //  生成账单 生成excel文档
            String bucketName = minioUtil.getBucketName();
            ExportParams exportParamBusinessOne = new ExportParams("京东业务对账单-汇总表", "京东业务对账单-汇总表", ExcelType.HSSF);
            Map<String, Object> paramsOneMap = new HashMap<>();
            paramsOneMap.put("title", exportParamBusinessOne);
            paramsOneMap.put("entity", BillJDCycleExcelVO.class);
            paramsOneMap.put("data", billJDCycleExcelVOList);
            ExportParams exportParam2 = new ExportParams(firstDayOfLastMonth.getMonthValue() + "月京东订单明细表", firstDayOfLastMonth.getMonthValue() + "月京东订单明细表", ExcelType.HSSF);
            Map<String, Object> paramsTwoMap = new HashMap<>();
            paramsTwoMap.put("title", exportParam2);
            paramsTwoMap.put("entity", BillJDInfoExcelVO.class);
            paramsTwoMap.put("data", jdOrderList);
            ExportParams exportParam3 = new ExportParams(firstDayOfLastMonth.getMonthValue() + "月京东售后明细表", firstDayOfLastMonth.getMonthValue() + "月京东售后明细表", ExcelType.HSSF);
            Map<String, Object> paramsThreeMap = new HashMap<>();
            paramsThreeMap.put("title", exportParam3);
            paramsThreeMap.put("entity", BillJDAfterSalesExcelVO.class);
            paramsThreeMap.put("data", jdAfterSaleList);
            // 将2个sheet封装
            List<Map<String, Object>> sheetsList = new ArrayList<>();
            sheetsList.add(paramsOneMap);
            sheetsList.add(paramsTwoMap);
            sheetsList.add(paramsThreeMap);
            Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
            log.info("京东业务对账单-汇总表生成 >>>> workbook:{}", workbook);
            String path = minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download", firstDayOfLastMonth.getMonthValue() + "月京东业务对账单-汇总表" + XLSX, false);
            userBill.setFilePath(path);
            userBill.setCreateTime(LocalDateTime.now());
            userBillMapper.deleteBill(year + "-" + month, userBill.getBillType());
            userBillMapper.insert(userBill);

            return Boolean.TRUE;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    @Override
    public boolean insertPayMKBAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertPayMKBAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertPayAccount(1, 1, now);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public boolean insertPayJDAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertPayJDAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertPayAccount(1, 2, now);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public boolean insertPayHDAccount(LocalDateTime now) {

        //加redis 定位任务锁
        RLock lock = redissonClient.getLock(USER_TASK_KEY + "insertPayHDAccount");

        try {

            lock.lock(10, TimeUnit.SECONDS);

            return insertPayAccount(1, 3, now);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public boolean insertJDAccount(LocalDateTime now) {
        return false;
    }

    private static @Nullable String getFileName(Integer billType, LocalDateTime now) {
        String fileName = null;
        //获取上个月第一天
        LocalDateTime firstDayOfLastMonth = now.withDayOfMonth(1).minusMonths(1);

        int year = firstDayOfLastMonth.getYear();
        int month = firstDayOfLastMonth.getMonthValue();
        if (billType == 1) {
            //交易流水账单
            //存入oss中  返回地址
            fileName = year + "年" + month + "月交易流水账单";
        } else if (billType == 2) {
            //餐补交易流水账单
            fileName = year + "年" + month + "月餐补流水账单";
        } else if (billType == 3) {
            //餐补交易流水账单
            fileName = year + "年" + month + "月现金流水账单";
        } else if (billType == 4) {
            //餐补交易流水账单
            fileName = year + "年" + month + "月退款流水账单";
        } else if (billType == 5) {
            //餐补交易流水账单
            fileName = year + "年" + month + "月支付流水账单";
        } else if (billType == 100) {
            fileName = year + "年" + month + "月末餐卡总账余额账单";
        } else if (billType == 6) {
            fileName = year + "年" + month + "月账户业务对账单";
        }
        return fileName;
    }

    /**
     * 获取账单时间集
     *
     * @param billType 1 交易流水账单 业务账单-汇总表
     *                 2餐补交易流水账单
     *                 3现金流水账单
     *                 4退款流水账单
     *                 5支付流水账单
     *                 6支付账单
     * @return
     */
    private @NotNull LambdaQueryWrapper<UserTransaction> getUserTransactionLambdaQueryWrapper(Integer billType, LocalDateTime now) {
        //获取上个月第一天
        Map<String, LocalDateTime> billTimeMap = getBillTimeMap(now);
        LocalDateTime localDateBegin = billTimeMap.get("begin");
        log.info("报表开始时间 >>>> time:{}", localDateBegin);
        // 获取这个月的第一天
        LocalDateTime localDateEnd = billTimeMap.get("end");
        log.info("报表结束时间 >>>> time:{}", localDateEnd);
        LambdaQueryWrapper<UserTransaction> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(UserTransaction::getTransactionTime, localDateBegin)
                .lt(UserTransaction::getTransactionTime, localDateEnd);
        log.info("报表sql生成 >>>> time:{}", queryWrapper);
        //餐补
        if (billType == 2) {
            queryWrapper.eq(UserTransaction::getAccountType, 1);
        }
        //现金
        if (billType == 3) {
            queryWrapper.eq(UserTransaction::getAccountType, 2);
        }
        //退款
        if (billType == 4) {
            queryWrapper.in(UserTransaction::getTransactionType, "3", "5", "8");
        }
        //充值
        if (billType == 5) {
            queryWrapper.in(UserTransaction::getTransactionType, "1", "6");
        }
        //支付
        if (billType == 6) {
            queryWrapper.in(UserTransaction::getTransactionType, "2", "4", "7", "10");
        }
        return queryWrapper;
    }

    /**
     * 餐补 现金 退款 标题
     *
     * @param billType
     * @return
     */
    public String getTitName(Integer billType, LocalDateTime now) {
        LocalDateTime localDateTime = now.withDayOfMonth(1).minusMonths(1);
        String titName = null;
        if (billType == 1) {
            //交易流水账单
            titName = localDateTime.getMonthValue() + "月交易流水账单";
        }
        if (billType == 2) {
            //餐补流水统计
            titName = localDateTime.getMonthValue() + "月餐补流水账单";
        }
        if (billType == 3) {
            //现金
            titName = localDateTime.getMonthValue() + "月现金流水账单";
        }
        if (billType == 4) {
            //退款
            titName = localDateTime.getMonthValue() + "月退款流水账单";
        }
        return titName;
    }

    /**
     * 交易流水标题
     *
     * @return
     */
    public List<BillTotalExcelVO> getListTotal(LocalDateTime now) {
        List<BillTotalExcelVO> billTotalExcelVOList = new ArrayList<>();
        //获取上个月第一天
        Map<String, LocalDateTime> billTimeMap = getBillTimeMap(now);
        LocalDateTime localDateBegin = billTimeMap.get("begin");
        LocalDateTime localDateEnd = billTimeMap.get("end");
        List<TransactionGroupVO> transactionGroupByType = userTransactionMapper.getTransactionGroupByType(localDateBegin, localDateEnd);

        log.info("交易流水账单:{}", JSON.toJSONString(transactionGroupByType));
        Map<Integer, BigDecimal> transactionGroupByTypeMap = UserTypeToNameUtil.getMapToBig(transactionGroupByType.stream().collect(Collectors.toMap(TransactionGroupVO::getTransactionCategory, a -> a)));
        UserTransactionGroupByAllVO groupByBeginTime = userTransactionMapper.getUserIdGroupByBeginTimeAll(localDateBegin);
        UserTransactionGroupByAllVO groupByEndTime = userTransactionMapper.getUserIdGroupByEndTimeAll(localDateEnd);

        log.info("期初:{}", JSON.toJSONString(groupByBeginTime));
        log.info("期末:{}", JSON.toJSONString(groupByEndTime));
        //期初 餐补
        BigDecimal beginCardAccount = groupByBeginTime != null ? groupByBeginTime.getCardAccount() : BigDecimal.ZERO;
        BigDecimal beginCashAccount = groupByBeginTime != null ? groupByBeginTime.getCashAccount() : BigDecimal.ZERO;

        //期末
        BigDecimal endCardAccount = groupByEndTime != null ? groupByEndTime.getCardAccount() : BigDecimal.ZERO;
        BigDecimal endCashAccount = groupByEndTime != null ? groupByEndTime.getCashAccount() : BigDecimal.ZERO;

        //充值
        BigDecimal reBigDecimal = transactionGroupByTypeMap.get(1);
        //退款
        BigDecimal deduBigDecimal = transactionGroupByTypeMap.get(3);
        //支付
        BigDecimal payBigDecimal = transactionGroupByTypeMap.get(2);
        //交易
        BigDecimal tranBigDecimal = reBigDecimal.add(deduBigDecimal).add(payBigDecimal);
        //期初值
        BigDecimal beginBigDecimal = beginCardAccount.add(beginCashAccount);
        //期末值
        BigDecimal endBigDecimal = endCardAccount.add(endCashAccount);
        billTotalExcelVOList.add(new BillTotalExcelVO(1, localDateBegin.getMonthValue() + "月交易流水账单金额合计：", tranBigDecimal));
        billTotalExcelVOList.add(new BillTotalExcelVO(2, localDateBegin.getMonthValue() + "月退款流水账单金额合计：", deduBigDecimal));
        billTotalExcelVOList.add(new BillTotalExcelVO(3, localDateBegin.getMonthValue() + "月支付流水账单金额合计：", payBigDecimal));
        billTotalExcelVOList.add(new BillTotalExcelVO(4, localDateBegin.getMonthValue() + "月充值流水账单金额合计：", reBigDecimal));
        billTotalExcelVOList.add(new BillTotalExcelVO(5, localDateBegin.getMonthValue() + "月交易流水账单期初值：", beginBigDecimal));
        billTotalExcelVOList.add(new BillTotalExcelVO(6, localDateBegin.getMonthValue() + "月交易流水账单期末值：", endBigDecimal));

        log.info("账单统计信息：{}", JSON.toJSONString(billTotalExcelVOList));
        return billTotalExcelVOList;
    }
}